From f2bf0964dfe90280c6a9d2e42f1a0518268c3e97 Mon Sep 17 00:00:00 2001 From: calvin-archastro Date: Fri, 14 Aug 2026 15:19:56 -0700 Subject: [PATCH 1/3] feat: add initial ArchAstro Rust SDK --- .github/workflows/ci.yml | 51 + .gitignore | 5 + Cargo.lock | 2316 + Cargo.toml | 44 + LICENSE | 22 + README.md | 59 + package-lock.json | 2648 + package.json | 22 + scripts/regenerate_sdk.sh | 25 + scripts/sdk-generator-config.json | 9 + specs/platform-openapi.json | 113972 +++++++++++++++++++++++++ src/blocking.rs | 19 + src/channel.rs | 851 + src/client.rs | 291 + src/error.rs | 87 + src/generated/auth.rs | 392 + src/generated/channels.rs | 1864 + src/generated/mod.rs | 17 + src/generated/types.rs | 4637 + src/generated/v1.rs | 20435 +++++ src/http.rs | 254 + src/lib.rs | 30 + src/session.rs | 36 + src/sse.rs | 72 + tests/channel_runtime_contract.rs | 141 + tests/generated_channel_contract.rs | 449 + tests/generated_rest_contract.rs | 19367 +++++ tests/generated_stream_contract.rs | 141 + tests/runtime.rs | 369 + tests/sse_runtime_contract.rs | 44 + tests/support/mod.rs | 204 + 31 files changed, 168873 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 package-lock.json create mode 100644 package.json create mode 100755 scripts/regenerate_sdk.sh create mode 100644 scripts/sdk-generator-config.json create mode 100644 specs/platform-openapi.json create mode 100644 src/blocking.rs create mode 100644 src/channel.rs create mode 100644 src/client.rs create mode 100644 src/error.rs create mode 100644 src/generated/auth.rs create mode 100644 src/generated/channels.rs create mode 100644 src/generated/mod.rs create mode 100644 src/generated/types.rs create mode 100644 src/generated/v1.rs create mode 100644 src/http.rs create mode 100644 src/lib.rs create mode 100644 src/session.rs create mode 100644 src/sse.rs create mode 100644 tests/channel_runtime_contract.rs create mode 100644 tests/generated_channel_contract.rs create mode 100644 tests/generated_rest_contract.rs create mode 100644 tests/generated_stream_contract.rs create mode 100644 tests/runtime.rs create mode 100644 tests/sse_runtime_contract.rs create mode 100644 tests/support/mod.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1ad2df0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,51 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 + with: + node-version: 20 + cache: npm + - run: npm ci --ignore-scripts + - run: npm audit --audit-level=high + - run: cargo fmt --all -- --check + - run: cargo clippy --all-features --all-targets -- -D warnings + - run: cargo test --all-features --locked + - name: REST contracts + run: cargo test --all-features --locked --test generated_rest_contract -- --ignored --test-threads=1 + - name: SSE contracts + run: cargo test --all-features --locked --test generated_stream_contract -- --ignored --test-threads=1 + - name: SSE fault contracts + run: cargo test --all-features --locked --test sse_runtime_contract -- --ignored --test-threads=1 + - name: Channel contracts + run: cargo test --all-features --locked --test generated_channel_contract -- --ignored --test-threads=1 + - name: Channel fault contracts + run: cargo test --all-features --locked --test channel_runtime_contract -- --ignored --test-threads=1 + + msrv: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: dtolnay/rust-toolchain@1.85.0 + - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 + - run: cargo check --locked --no-default-features --features rustls-tls diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d4cf6b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/target/ +/node_modules/ +*.rs.bk +.DS_Store + diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6b26845 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2316 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + +[[package]] +name = "archastro" +version = "0.1.0" +dependencies = [ + "async-trait", + "chrono", + "futures-core", + "futures-util", + "httpmock", + "reqwest", + "reqwest-eventsource", + "serde", + "serde_json", + "serde_urlencoded", + "serial_test", + "thiserror 2.0.20", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "url", +] + +[[package]] +name = "assert-json-diff" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-object-pool" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ac0219111eb7bb7cb76d4cf2cb50c598e7ae549091d3616f9e95442c18486f" +dependencies = [ + "async-lock", + "event-listener", +] + +[[package]] +name = "async-trait" +version = "0.1.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +dependencies = [ + "serde", +] + +[[package]] +name = "cc" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "data-encoding" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid", + "crypto-common 0.2.2", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "eventsource-stream" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74fef4569247a5f429d9156b9d0a2599914385dd189c539334c625d8099d90ab" +dependencies = [ + "futures-core", + "nom", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "find-msvc-tools" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-timer" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "rand_core", + "wasm-bindgen", +] + +[[package]] +name = "h2" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "headers" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" +dependencies = [ + "base64", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1 0.10.7", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "httpmock" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "511f510e9b1888d67f10bab4397f8b019d2a9b249a2c10acbce2d705b1b32e26" +dependencies = [ + "assert-json-diff", + "async-object-pool", + "async-trait", + "base64", + "bytes", + "crossbeam-utils", + "form_urlencoded", + "futures-timer", + "futures-util", + "headers", + "http", + "http-body-util", + "hyper", + "hyper-util", + "path-tree", + "regex", + "serde", + "serde_json", + "serde_regex", + "similar", + "stringmetrics", + "tabwriter", + "thiserror 2.0.20", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hybrid-array" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" +dependencies = [ + "typenum", +] + +[[package]] +name = "hyper" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots 1.0.9", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "ipnet" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a756c3fac73139e83f14c2d742155dd2b78d3ee56597b419a0579b7bdd6dd78" + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mio" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "openssl" +version = "0.10.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "path-tree" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a97453bc21a968f722df730bfe11bd08745cb50d1300b0df2bda131dece136" +dependencies = [ + "smallvec", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "zerovec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.20", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" +dependencies = [ + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.20", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "native-tls", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots 1.0.9", +] + +[[package]] +name = "reqwest-eventsource" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632c55746dbb44275691640e7b40c907c16a2dc1a5842aa98aaec90da6ec6bde" +dependencies = [ + "eventsource-stream", + "futures-core", + "futures-timer", + "mime", + "nom", + "pin-project-lite", + "reqwest", + "thiserror 1.0.69", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0527518605e68109d875e248ea259b6758801cf165e4b2c2733ae3b51f12535a" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_regex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafc8d0c5330cecff10f16b459b479fd9acaa5b4acd7167301414e21b0057012" +dependencies = [ + "regex", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serial_test" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "699f4197115b8a7e7ff19c9a315a4bd6fffec26cc4626ef45ecaea389e081c6d" +dependencies = [ + "futures-executor", + "futures-util", + "log", + "once_cell", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e153fc76e1c6a068703d6d29c508a0b15c061c4b7e43da59cc097bc342673c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "sha1" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stringmetrics" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b3c8667cd96245cbb600b8dec5680a7319edd719c5aa2b5d23c6bff94f39765" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tabwriter" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fce91f2f0ec87dff7e6bcbbeb267439aa1188703003c6055193c821487400432" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl 2.0.20", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "tinystr" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17a073bfed563fa236697a068031408a93cd9522e08abf9933ead3e73411bd71" +dependencies = [ + "futures-util", + "log", + "native-tls", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tungstenite", + "webpki-roots 0.26.11", +] + +[[package]] +name = "tokio-util" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "libc", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48ac77174b19c110a50ab2128b24215ac9cb40e0e12e093fb602d175c569d22" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "native-tls", + "rand", + "rustls", + "rustls-pki-types", + "sha1 0.11.0", + "thiserror 2.0.20", + "url", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b7777d5cc23d0e91404e53ce2d5e8ec7acae3026b16233dba62cd3246457950" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c435338968042f4f59a557f690a253676d47ce13ceb55d70100e7facf6620a30" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.9", +] + +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + +[[package]] +name = "zerotrie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b5c6b5976d66c1d703c4fd17d3f5e43c8cedaacf604961b171adc7130896d8" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47402523226a02bfe5230160dc3ccc089aa6f6f19e7fcbb4e6f824bbb1b4aa62" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f2e6af6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "archastro" +version = "0.1.0" +edition = "2024" +rust-version = "1.85" +description = "Official Rust SDK for the ArchAstro platform" +license = "MIT" +repository = "https://github.com/ArchAstro/archastro-rust" +keywords = ["archastro", "sdk", "api", "sse", "phoenix"] +categories = ["api-bindings", "web-programming::http-client", "web-programming::websocket"] +include = ["/src/**", "/tests/**", "/Cargo.toml", "/README.md", "/LICENSE"] + +[features] +default = ["rustls-tls", "blocking"] +rustls-tls = ["reqwest/rustls-tls", "tokio-tungstenite/rustls-tls-webpki-roots"] +native-tls = ["reqwest/native-tls", "tokio-tungstenite/native-tls"] +blocking = [] + +[dependencies] +async-trait = "0.1.89" +chrono = { version = "0.4.41", features = ["serde"] } +futures-core = "0.3.31" +futures-util = "0.3.31" +reqwest = { version = "0.12.24", default-features = false, features = ["json", "stream"] } +reqwest-eventsource = "0.6.0" +serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.145" +serde_urlencoded = "0.7.1" +thiserror = "2.0.17" +tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "sync", "time", "net"] } +tokio-stream = { version = "0.1.17", features = ["sync"] } +tokio-tungstenite = { version = "0.30.0", default-features = false, features = ["connect", "url"] } +url = "2.5.7" + +[dev-dependencies] +httpmock = "0.8.2" +serial_test = "3.2.0" + +[lints.rust] +unsafe_code = "forbid" +missing_docs = "warn" + +[lints.clippy] +all = { level = "warn", priority = -1 } diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ea48b17 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2026 ArchAstro Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..10b06c9 --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +# ArchAstro Rust SDK + +Official, generated-first Rust client for ArchAstro: typed HTTP resources, +automatic single-flight token refresh, SSE streams, and Phoenix channels. + +```toml +[dependencies] +archastro = "0.1" +``` + +```rust,no_run +use archastro::Client; + +#[tokio::main] +async fn main() -> archastro::Result<()> { + let client = Client::builder() + .secret_key(std::env::var("ARCHASTRO_SECRET_KEY").unwrap()) + .build()?; + + let status = client.v1().status().ping().await?; + println!("{status:?}"); + Ok(()) +} +``` + +1. Async API: every generated HTTP call is `async` and uses a cloneable, + pooled `reqwest::Client`. +2. Blocking API: default `blocking` feature adds a `_blocking` variant to + non-streaming methods. Do not call it from inside a Tokio runtime. +3. SSE: streaming endpoints return `SseStream`, implementing + `futures_core::Stream` with reconnection and last-event-ID support. +4. Channels: `client.socket().await?.connect().await?` opens a Phoenix v2 + socket; generated facades provide typed join responses, messages, and push + streams. The runtime reconnects, rejoins, verifies heartbeats, and buffers + pushes while a desired channel is reconnecting. +5. Auth: secret keys, publishable keys, bearer/system tokens, and + `Client::with_credentials` are supported. Concurrent 401s share one + generation-fenced refresh because refresh tokens are single-use. +6. App sessions: configure a `SessionStore`, then use `restore_session`, + `install_app_session`, and `sign_out`. Refresh-token rotations are written + back after the in-memory bearer is updated. + +## Development + +```bash +npm ci +./scripts/regenerate_sdk.sh --local ../archastro-openapi +cargo fmt --all -- --check +cargo clippy --all-features --all-targets -- -D warnings +cargo test --all-features +cargo test --all-features --test generated_rest_contract -- --ignored --test-threads=1 +cargo test --all-features --test generated_stream_contract -- --ignored --test-threads=1 +cargo test --all-features --test generated_channel_contract -- --ignored --test-threads=1 +cargo test --all-features --test sse_runtime_contract -- --ignored --test-threads=1 +cargo test --all-features --test channel_runtime_contract -- --ignored --test-threads=1 +``` + +Generated files carry a content hash and must only be changed through +`@archastro/sdk-generator`. diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..7d20161 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2648 @@ +{ + "name": "archastro-rust-tooling", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "archastro-rust-tooling", + "devDependencies": { + "@archastro/channel-harness": "latest", + "@archastro/sdk-generator": "latest", + "@stoplight/prism-cli": "5.16.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@archastro/channel-harness": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@archastro/channel-harness/-/channel-harness-0.7.0.tgz", + "integrity": "sha512-jQsyzCuqzirzeT7846Y9/la9PfC8hyC1IOEqLIuOJR5CyhExuSY9ZfqYyjE1kuyq73A9/44I+SQmOVtK8dKgcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@archastro/sdk-generator": "^0.9.0", + "ajv": "^8.12.0", + "ajv-formats": "^3.0.1", + "ws": "^8.18.0", + "yaml": "^2.4.0" + }, + "bin": { + "channel-harness": "dist/bin.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@archastro/channel-harness/node_modules/@archastro/sdk-generator": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@archastro/sdk-generator/-/sdk-generator-0.9.0.tgz", + "integrity": "sha512-UvIGwScYJjfDWXtM02O2s4Am0F6MsKXD+8wSlMVyExZ4oHmCalu2qHQRAGNVhBPzLu9jlynPz1++UE4o+kgOpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.12.0", + "ajv-formats": "^3.0.1", + "yaml": "^2.4.0" + }, + "bin": { + "sdk-generator": "dist/index.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@archastro/sdk-generator": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@archastro/sdk-generator/-/sdk-generator-0.11.0.tgz", + "integrity": "sha512-ZYcgMoBiCudoHh64i/Qe/3EQyH68jfr6AqQ91JLgmanGlILeN4ko0gDhMcBQ1VxT59L0ZzlrR7TTkU9XpHk64w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.12.0", + "ajv-formats": "^3.0.1", + "yaml": "^2.4.0" + }, + "bin": { + "sdk-generator": "dist/index.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@faker-js/faker": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.6.0.tgz", + "integrity": "sha512-3RQHgEtvL1Frl/d1cSreo7qhJ3Gk1OdNUai/CtZ8G+wYeRQnJih3s9xJ9/kgYekPQRdwgh0HXRPqMlzWGwivIQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0", + "npm": ">=10" + } + }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@jsep-plugin/regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@nodable/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@scarf/scarf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", + "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0" + }, + "node_modules/@stoplight/http-spec": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@stoplight/http-spec/-/http-spec-7.1.0.tgz", + "integrity": "sha512-Z2XqKX2SV8a1rrgSzFqccX2TolfcblT+l4pNvUU+THaLl50tKDoeidwWWZTzYUzqU0+UV97ponvqEbWWN3PaXg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@stoplight/json": "^3.18.1", + "@stoplight/json-schema-generator": "1.0.2", + "@stoplight/types": "14.1.0", + "@types/json-schema": "7.0.11", + "@types/swagger-schema-official": "~2.0.22", + "@types/type-is": "^1.6.3", + "fnv-plus": "^1.3.1", + "lodash": "^4.17.21", + "openapi3-ts": "^2.0.2", + "postman-collection": "^4.1.3", + "tslib": "^2.6.2", + "type-is": "^1.6.18" + }, + "engines": { + "node": ">=14.13" + } + }, + "node_modules/@stoplight/http-spec/node_modules/@stoplight/types": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-14.1.0.tgz", + "integrity": "sha512-fL8Nzw03+diALw91xHEHA5Q0WCGeW9WpPgZQjodNUWogAgJ56aJs03P9YzsQ1J6fT7/XjDqHMgn7/RlsBzB/SQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + } + }, + "node_modules/@stoplight/json": { + "version": "3.21.7", + "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.21.7.tgz", + "integrity": "sha512-xcJXgKFqv/uCEgtGlPxy3tPA+4I+ZI4vAuMJ885+ThkTHFVkC+0Fm58lA9NlsyjnkpxFh4YiQWpH+KefHdbA0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@stoplight/ordered-object-literal": "^1.0.3", + "@stoplight/path": "^1.3.2", + "@stoplight/types": "^13.6.0", + "jsonc-parser": "~2.2.1", + "lodash": "^4.17.21", + "safe-stable-stringify": "^1.1" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/@stoplight/json-schema-generator": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stoplight/json-schema-generator/-/json-schema-generator-1.0.2.tgz", + "integrity": "sha512-FzSLFoIZc6Lmw3oRE7kU6YUrl5gBmUs//rY59jdFipBoSyTPv5NyqeyTg5mvT6rY1F3qTLU3xgzRi/9Pb9eZpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-fetch": "^3.1.5", + "json-promise": "1.1.x", + "minimist": "1.2.6", + "mkdirp": "0.5.x", + "pretty-data": "0.40.x" + }, + "bin": { + "json-schema-generator": "bin/cli.js" + } + }, + "node_modules/@stoplight/json-schema-merge-allof": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/@stoplight/json-schema-merge-allof/-/json-schema-merge-allof-0.7.8.tgz", + "integrity": "sha512-JTDt6GYpCWQSb7+UW1P91IAp/pcLWis0mmEzWVFcLsrNgtUYK7JLtYYz0ZPSR4QVL0fJ0YQejM+MPq5iNDFO4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "compute-lcm": "^1.1.0", + "json-schema-compare": "^0.2.2", + "lodash": "^4.17.4" + } + }, + "node_modules/@stoplight/json-schema-ref-parser": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@stoplight/json-schema-ref-parser/-/json-schema-ref-parser-10.0.0.tgz", + "integrity": "sha512-EibmayoGsMCIJOEKNvmsrAq37/M7A/rceY8ZAKX8rhwPThgkJ4QTPF0VhgGyfuq9P6i0EQQXM/x6nL7S2uPGsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@stoplight/path": "^1.3.2", + "@stoplight/yaml": "^4.0.2", + "call-me-maybe": "^1.0.1", + "url": "^0.11.3" + } + }, + "node_modules/@stoplight/json-schema-sampler": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@stoplight/json-schema-sampler/-/json-schema-sampler-0.3.0.tgz", + "integrity": "sha512-G7QImi2xr9+8iPEg0D9YUi1BWhIiiEm19aMb91oWBSdxuhezOAqqRP3XNY6wczHV9jLWW18f+KkghTy9AG0BQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.7", + "json-pointer": "^0.6.1" + } + }, + "node_modules/@stoplight/json/node_modules/@stoplight/types": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.20.0.tgz", + "integrity": "sha512-2FNTv05If7ib79VPDA/r9eUet76jewXFH2y2K5vuge6SXbRHtWBhcaRmu+6QpF4/WRNoJj5XYRSwLGXDxysBGA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + } + }, + "node_modules/@stoplight/ordered-object-literal": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@stoplight/ordered-object-literal/-/ordered-object-literal-1.0.5.tgz", + "integrity": "sha512-COTiuCU5bgMUtbIFBuyyh2/yVVzlr5Om0v5utQDgBCuQUOPgU1DwoffkTfg4UBQOvByi5foF4w4T+H9CoRe5wg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/@stoplight/path": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@stoplight/path/-/path-1.3.2.tgz", + "integrity": "sha512-lyIc6JUlUA8Ve5ELywPC8I2Sdnh1zc1zmbYgVarhXIp9YeAB0ReeqmGEOWNtlHkbP2DAA1AL65Wfn2ncjK/jtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/@stoplight/prism-cli": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@stoplight/prism-cli/-/prism-cli-5.16.0.tgz", + "integrity": "sha512-lkkchTfCVwRjo4GC/lDOK4dFZ8Sxggw4O0V5lpiIKPHRpm1MFnLDsjA55PuP5EZHcmV0jpcQn/qVBOoN2YRVtg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@scarf/scarf": "^1.4.0", + "@stoplight/json": "3.21.7", + "@stoplight/json-schema-ref-parser": "10.0.0", + "@stoplight/prism-core": "^5.16.0", + "@stoplight/prism-http": "^5.16.0", + "@stoplight/prism-http-server": "^5.16.0", + "@stoplight/types": "^14.1.0", + "chalk": "^4.1.2", + "chokidar": "^3.5.2", + "fp-ts": "^2.11.5", + "json-schema-faker": "0.5.9", + "jsonrepair": "^3.12.0", + "lodash": "^4.17.23", + "node-fetch": "^2.6.5", + "pino": "^6.13.3", + "signale": "^1.4.0", + "split2": "^4.2.0", + "tslib": "^2.3.1", + "uri-template-lite": "^22.9.0", + "urijs": "^1.19.11", + "yargs": "^16.2.0" + }, + "bin": { + "prism": "dist/index.js" + }, + "engines": { + "node": ">=24.18.0" + } + }, + "node_modules/@stoplight/prism-core": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@stoplight/prism-core/-/prism-core-5.16.0.tgz", + "integrity": "sha512-akuIOfe2jvyPbAu9XOIXP+UpiVl+rctU8laJsxvWsFX2X4m8rANTWC2/682/f35MtJv3h5jCYB4tAt8qJWx/OA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@scarf/scarf": "^1.4.0", + "fp-ts": "^2.11.5", + "lodash": "^4.17.21", + "pino": "^6.13.3", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=24.18.0" + } + }, + "node_modules/@stoplight/prism-http": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@stoplight/prism-http/-/prism-http-5.16.0.tgz", + "integrity": "sha512-+ZDU+33I3K7+uO2Ma1dZBgQRD4RarfBzHQcU/o3VMA850ez39H7AqJpMugeG2xKnzzzs8DNA442K2wfT1Ve9NA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@faker-js/faker": "^10.4.0", + "@scarf/scarf": "^1.4.0", + "@stoplight/http-spec": "^7.1.0", + "@stoplight/json": "3.21.7", + "@stoplight/json-schema-merge-allof": "0.7.8", + "@stoplight/json-schema-ref-parser": "10.0.0", + "@stoplight/json-schema-sampler": "0.3.0", + "@stoplight/prism-core": "^5.16.0", + "@stoplight/types": "^14.1.0", + "@stoplight/yaml": "^4.2.3", + "abstract-logging": "^2.0.1", + "accepts": "^1.3.7", + "ajv": "^8.20.0", + "ajv-formats": "^2.1.1", + "caseless": "^0.12.0", + "chalk": "^4.1.2", + "content-type": "^1.0.4", + "fp-ts": "^2.11.5", + "http-proxy-agent": "^9.0.0", + "https-proxy-agent": "^9.0.0", + "json-schema-faker": "0.5.8", + "lodash": "^4.17.23", + "node-fetch": "^2.6.5", + "parse-multipart-data": "^1.5.0", + "pino": "^6.13.3", + "seedrandom": "^3.0.5", + "tslib": "^2.3.1", + "type-is": "^1.6.18", + "uri-template-lite": "^22.9.0", + "whatwg-mimetype": "^3.0.0" + }, + "engines": { + "node": ">=24.18.0" + } + }, + "node_modules/@stoplight/prism-http-server": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@stoplight/prism-http-server/-/prism-http-server-5.16.0.tgz", + "integrity": "sha512-vdbxE45cNjm4DNg/4igLqrS+9LyL5TSrf3FUYGDLBRcW5YGd5JvDdoMOi7nlAnilK9gpa2cHQbxEYkomZkJj7Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@scarf/scarf": "^1.4.0", + "@stoplight/prism-core": "^5.16.0", + "@stoplight/prism-http": "^5.16.0", + "@stoplight/types": "^14.1.0", + "fast-xml-parser": "^5.5.7", + "fp-ts": "^2.11.5", + "io-ts": "^2.2.16", + "lodash": "^4.17.23", + "micri": "^4.3.0", + "node-fetch": "^2.6.5", + "parse-prefer-header": "1.0.0", + "tslib": "^2.3.1", + "type-is": "^1.6.18" + }, + "engines": { + "node": ">=24.18.0" + } + }, + "node_modules/@stoplight/prism-http/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@stoplight/prism-http/node_modules/json-schema-faker": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/json-schema-faker/-/json-schema-faker-0.5.8.tgz", + "integrity": "sha512-sqzPEbEDlpiH8U1tfmJHScXHy52onvMxITPsHyhe/jhS83g8TX6ruvRqt/ot1bXUPRsh7Ps1sWqJiBxIXmW5Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-schema-ref-parser": "^6.1.0", + "jsonpath-plus": "^10.1.0" + }, + "bin": { + "jsf": "bin/gen.cjs" + } + }, + "node_modules/@stoplight/types": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-14.1.1.tgz", + "integrity": "sha512-/kjtr+0t0tjKr+heVfviO9FrU/uGLc+QNX3fHJc19xsCNYqU7lVhaXxDmEID9BZTjG+/r9pK9xP/xU02XGg65g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + } + }, + "node_modules/@stoplight/yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@stoplight/yaml/-/yaml-4.3.0.tgz", + "integrity": "sha512-JZlVFE6/dYpP9tQmV0/ADfn32L9uFarHWxfcRhReKUnljz1ZiUM5zpX+PH8h5CJs6lao3TuFqnPm9IJJCEkE2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@stoplight/ordered-object-literal": "^1.0.5", + "@stoplight/types": "^14.1.1", + "@stoplight/yaml-ast-parser": "0.0.50", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=10.8" + } + }, + "node_modules/@stoplight/yaml-ast-parser": { + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.50.tgz", + "integrity": "sha512-Pb6M8TDO9DtSVla9yXSTAxmo9GVEouq5P40DWXdOie69bXogZTkgvopCq+yEvTMA0F6PEvdJmbtTV3ccIp11VQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz", + "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/swagger-schema-official": { + "version": "2.0.25", + "resolved": "https://registry.npmjs.org/@types/swagger-schema-official/-/swagger-schema-official-2.0.25.tgz", + "integrity": "sha512-T92Xav+Gf/Ik1uPW581nA+JftmjWPgskw/WBf4TJzxRG/SJ+DfNnNE+WuZ4mrXuzflQMqMkm1LSYjzYW7MB1Cg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/type-is": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@types/type-is/-/type-is-1.6.7.tgz", + "integrity": "sha512-gEsh7n8824nusZ2Sidh6POxNsIdTSvIAl5gXbeFj+TUaD1CO2r4i7MQYNMfEQkChU42s2bVWAda6x6BzIhtFbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/abstract-logging": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", + "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anynum": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz", + "integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/charset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz", + "integrity": "sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/compute-gcd": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/compute-gcd/-/compute-gcd-1.2.1.tgz", + "integrity": "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==", + "dev": true, + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, + "node_modules/compute-lcm": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/compute-lcm/-/compute-lcm-1.1.2.tgz", + "integrity": "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==", + "dev": true, + "dependencies": { + "compute-gcd": "^1.2.1", + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-4.1.2.tgz", + "integrity": "sha512-TyGmBcbDTZXcb2cj5MV89DrF42DKvb3y5DDUNh95iO+IMeAzMkVSxK1PZRrRIpc9yg8U2GhGdbofNa0LS/a4Bw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fast-xml-builder": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.1.tgz", + "integrity": "sha512-pIM/1n3ntFXKYrUZwW7QCK0gAW7XY+wzj1YMIV3tLDvPj/V+zTGJK5e3/4WJfwj0qWw2ElNXiTixda/R+3YSug==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.6.2", + "xml-naming": "^0.3.0" + } + }, + "node_modules/fast-xml-builder/node_modules/xml-naming": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.3.0.tgz", + "integrity": "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.8.0.tgz", + "integrity": "sha512-6bIM7fsJxeo3uXv7OncQYsBAMPJ7V16Slahl/6M98C/i2q+vB1+4a0MtrvYwDFEUrwDSbAmeLDRXsOBwrL7yAg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.2.0", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.3.0", + "xml-naming": "^0.1.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flatstr": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz", + "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fnv-plus": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/fnv-plus/-/fnv-plus-1.3.1.tgz", + "integrity": "sha512-Gz1EvfOneuFfk4yG458dJ3TLJ7gV19q3OM/vVvvHf7eT02Hm1DleB4edsia6ahbKgAYxO9gvyQ1ioWZR+a00Yw==", + "dev": true, + "license": "MIT" + }, + "node_modules/foreach": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", + "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/format-util": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.5.tgz", + "integrity": "sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/fp-ts": { + "version": "2.16.11", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.11.tgz", + "integrity": "sha512-LaI+KaX2NFkfn1ZGHoKCmcfv7yrZsC3b8NtWsTVQeHkq4F27vI5igUuO53sxqDEa2gNQMHFPmpojDw/1zmUK7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handler-agent": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/handler-agent/-/handler-agent-0.2.0.tgz", + "integrity": "sha512-cUduQxa5p3TFtGmb55mrRbkk/3EJCsLSeFrCIuTakQHQlYVWXeW2L9IUQUHyoHLI4UgpBNaN2JrZ0He1jPu+vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-proxy-agent": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-9.1.0.tgz", + "integrity": "sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "9.0.0", + "debug": "^4.3.4", + "proxy-agent-negotiate": "1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/http-reasons": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/http-reasons/-/http-reasons-0.1.0.tgz", + "integrity": "sha512-P6kYh0lKZ+y29T2Gqz+RlC9WBLhKe8kDmcJ+A+611jFfxdPsbMRQ5aNmFRM3lENqFkK+HTTL+tlQviAiv0AbLQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/https-proxy-agent": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz", + "integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "9.0.0", + "debug": "^4.3.4", + "proxy-agent-negotiate": "1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/io-ts": { + "version": "2.2.22", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.22.tgz", + "integrity": "sha512-FHCCztTkHoV9mdBsHpocLpdTAfh956ZQcIkWQxxS0U5HT53vtrcuYdQneEJKH6xILaLNzXVl2Cvwtoy8XNN0AA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "fp-ts": "^2.5.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/js-yaml": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.3.0.tgz", + "integrity": "sha512-muutsYr+e2+d3rTgUGslq5rxbBlUy3cJ61IsHag2QNDQV+7zXWjkUpmALIajhrlLlrgRUiymj6U3zUr/TMK84Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.mjs" + } + }, + "node_modules/jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-pointer": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", + "integrity": "sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "foreach": "^2.0.4" + } + }, + "node_modules/json-promise": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/json-promise/-/json-promise-1.1.8.tgz", + "integrity": "sha512-rz31P/7VfYnjQFrF60zpPTT0egMPlc8ZvIQHWs4ZtNZNnAXRmXo6oS+6eyWr5sEMG03OVhklNrTXxiIRYzoUgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "*" + } + }, + "node_modules/json-schema-compare": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/json-schema-compare/-/json-schema-compare-0.2.2.tgz", + "integrity": "sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.4" + } + }, + "node_modules/json-schema-faker": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/json-schema-faker/-/json-schema-faker-0.5.9.tgz", + "integrity": "sha512-fNKLHgDvfGNNTX1zqIjqFMJjCLzJ2kvnJ831x4aqkAoeE4jE2TxvpJdhOnk3JU3s42vFzmXvkpbYzH5H3ncAzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-schema-ref-parser": "^6.1.0", + "jsonpath-plus": "^10.3.0" + }, + "bin": { + "jsf": "bin/gen.cjs" + } + }, + "node_modules/json-schema-ref-parser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-6.1.0.tgz", + "integrity": "sha512-pXe9H1m6IgIpXmE5JSb8epilNTGsmTb2iPohAXpOdhqGFbQjNeHHsZxU+C8w6T81GZxSPFLeUoqDJmzxx5IGuw==", + "deprecated": "Please switch to @apidevtools/json-schema-ref-parser", + "dev": true, + "license": "MIT", + "dependencies": { + "call-me-maybe": "^1.0.1", + "js-yaml": "^3.12.1", + "ono": "^4.0.11" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonc-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.2.1.tgz", + "integrity": "sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonpath-plus": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.4.0.tgz", + "integrity": "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" + }, + "bin": { + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/jsonrepair": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/jsonrepair/-/jsonrepair-3.15.0.tgz", + "integrity": "sha512-wy8OTjwsJwQRnQJkKnMJJ9vcytRdBPAgIF/Hy6+s1dAj42BHMKiyL8JzEieIl3JY7idt8eyHwBWTO8mh/+mtwA==", + "dev": true, + "license": "ISC", + "bin": { + "jsonrepair": "bin/cli.js" + } + }, + "node_modules/liquid-json": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/liquid-json/-/liquid-json-0.3.1.tgz", + "integrity": "sha512-wUayTU8MS827Dam6MxgD72Ui+KOSF+u/eIqpatOtjnvgJ0+mnDq33uC2M7J0tPK+upe/DpUAuK4JUU89iBoNKQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micri": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/micri/-/micri-4.5.1.tgz", + "integrity": "sha512-AtvnSBGFglNr+iqs5gufpHT9xRXUabgu9vYEnQYPXSBs+nLSBvmUS5Mzg+3LJ9eQBrNA1o5M49WeqiX1f+d2sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "handler-agent": "0.2.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-format": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mime-format/-/mime-format-2.0.1.tgz", + "integrity": "sha512-XxU3ngPbEnrYnNbIX+lYSaYg0M01v6p2ntd2YaFksTu0vayaw5OJvbdRyWs07EYRlLED5qadUZ+xo+XhOvFhwg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "charset": "^1.0.0" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ono": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/ono/-/ono-4.0.11.tgz", + "integrity": "sha512-jQ31cORBFE6td25deYeD80wxKBMj+zBmHTrVxnc6CKhx8gho6ipmWM5zj/oeoqioZ99yqBls9Z/9Nss7J26G2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "format-util": "^1.0.3" + } + }, + "node_modules/openapi3-ts": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/openapi3-ts/-/openapi3-ts-2.0.2.tgz", + "integrity": "sha512-TxhYBMoqx9frXyOgnRHufjQfPXomTIHYKhSKJ6jHfj13kS8OEIhvmE8CTuQyKtjjWttAjX5DPxM1vmalEpo8Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "yaml": "^1.10.2" + } + }, + "node_modules/openapi3-ts/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/parse-multipart-data": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/parse-multipart-data/-/parse-multipart-data-1.5.0.tgz", + "integrity": "sha512-ck5zaMF0ydjGfejNMnlo5YU2oJ+pT+80Jb1y4ybanT27j+zbVP/jkYmCrUGsEln0Ox/hZmuvgy8Ra7AxbXP2Mw==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-prefer-header": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-prefer-header/-/parse-prefer-header-1.0.0.tgz", + "integrity": "sha512-+WJ3ncCrKOExuxF06XyKWS8bLkLttnlm6YPMZIFIUXNd09Xy0N2JISudxCaY+luDm43yTnHMHVU3zte4G2gN4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.camelcase": "^4.3.0" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-expression-matcher": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz", + "integrity": "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pino": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-6.14.0.tgz", + "integrity": "sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-redact": "^3.0.0", + "fast-safe-stringify": "^2.0.8", + "flatstr": "^1.0.12", + "pino-std-serializers": "^3.1.0", + "process-warning": "^1.0.0", + "quick-format-unescaped": "^4.0.3", + "sonic-boom": "^1.0.2" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-std-serializers": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz", + "integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postman-collection": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.5.0.tgz", + "integrity": "sha512-152JSW9pdbaoJihwjc7Q8lc3nPg/PC9lPTHdMk7SHnHhu/GBJB7b2yb9zG7Qua578+3PxkQ/HYBuXpDSvsf7GQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@faker-js/faker": "5.5.3", + "file-type": "3.9.0", + "http-reasons": "0.1.0", + "iconv-lite": "0.6.3", + "liquid-json": "0.3.1", + "lodash": "4.17.21", + "mime-format": "2.0.1", + "mime-types": "2.1.35", + "postman-url-encoder": "3.0.5", + "semver": "7.6.3", + "uuid": "8.3.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-collection/node_modules/@faker-js/faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-R11tGE6yIFwqpaIqcfkcg7AICXzFg14+5h5v0TfF/9+RMDL6jhzCy/pxHVOfbALGdtVYdt6JdR21tuxEgl34dw==", + "deprecated": "Please update to a newer version.", + "dev": true, + "license": "MIT" + }, + "node_modules/postman-url-encoder": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postman-url-encoder/-/postman-url-encoder-3.0.5.tgz", + "integrity": "sha512-jOrdVvzUXBC7C+9gkIkpDJ3HIxOHTIqjpQ4C1EMt1ZGeMvSEpbFCKq23DEfgsj46vMnDgyQf+1ZLp2Wm+bKSsA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pretty-data": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/pretty-data/-/pretty-data-0.40.0.tgz", + "integrity": "sha512-YFLnEdDEDnkt/GEhet5CYZHCvALw6+Elyb/tp8kQG03ZSIuzeaDWpZYndCXwgqu4NAjh1PI534dhDS1mHarRnQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/process-warning": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", + "integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/proxy-agent-negotiate": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz", + "integrity": "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "kerberos": "^2.0.0" + }, + "peerDependenciesMeta": { + "kerberos": { + "optional": true + } + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==", + "dev": true, + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", + "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.3.2", + "figures": "^2.0.0", + "pkg-conf": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/signale/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/signale/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/signale/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sonic-boom": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz", + "integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "flatstr": "^1.0.12" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strnum": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.2.tgz", + "integrity": "sha512-rDG3Ah4TV0k1hWvLSzkZtMmLN9+eS+h3knq4MP6A42Y3Yh5qGNnOUs1jJkoSr8FG5dsL28c7KgkIBzSEykqtuw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "anynum": "^1.0.1" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-template-lite": { + "version": "22.9.0", + "resolved": "https://registry.npmjs.org/uri-template-lite/-/uri-template-lite-22.9.0.tgz", + "integrity": "sha512-cmGZaykSWEQ5UXKaGKnUS8zFvfp8j1Jvn7dlq3P7tGd5XeybXcfo0xnVBRWiNEp80nO1GYgCLwoaRJ8WMmmk3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/uuid": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/validate.io-array": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz", + "integrity": "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/validate.io-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz", + "integrity": "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==", + "dev": true + }, + "node_modules/validate.io-integer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz", + "integrity": "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==", + "dev": true, + "dependencies": { + "validate.io-number": "^1.0.3" + } + }, + "node_modules/validate.io-integer-array": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz", + "integrity": "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==", + "dev": true, + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-integer": "^1.0.4" + } + }, + "node_modules/validate.io-number": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz", + "integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==", + "dev": true + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz", + "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9002188 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "archastro-rust-tooling", + "private": true, + "description": "Generator, Prism, and channel-harness tooling for the ArchAstro Rust SDK.", + "scripts": { + "regenerate": "bash scripts/regenerate_sdk.sh" + }, + "devDependencies": { + "@archastro/channel-harness": "latest", + "@archastro/sdk-generator": "latest", + "@stoplight/prism-cli": "5.16.0" + }, + "overrides": { + "fast-uri": "4.1.2", + "fast-xml-parser": "5.8.0", + "js-yaml": "5.3.0", + "lodash": "4.18.1", + "uuid": "11.1.1", + "ws": "8.21.0" + }, + "engines": { "node": ">=20" } +} diff --git a/scripts/regenerate_sdk.sh b/scripts/regenerate_sdk.sh new file mode 100755 index 0000000..362ed36 --- /dev/null +++ b/scripts/regenerate_sdk.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License. +# Regenerate typed Rust sources and contract tests from the canonical spec. + +set -euo pipefail +cd "$(dirname "$0")/.." + +spec_dest="specs/platform-openapi.json" +config="scripts/sdk-generator-config.json" + +if [[ "${1:-}" == "--local" ]]; then + source_root="${2:?usage: regenerate_sdk.sh --local }" + cp "$source_root/specs/platform-openapi.json" "$spec_dest" + generator="${ARCHASTRO_SDK_GENERATOR_BIN:-$source_root/packages/sdk-generator/dist/index.js}" +else + ref="${ARCHASTRO_OPENAPI_REF:-main}" + curl -fsSL "https://raw.githubusercontent.com/ArchAstro/archastro-openapi/$ref/specs/platform-openapi.json" -o "$spec_dest" + generator="${ARCHASTRO_SDK_GENERATOR_BIN:-node_modules/.bin/sdk-generator}" +fi + +node "$generator" --spec "$spec_dest" --config "$config" --lang rust --out . +node "$generator" --spec "$spec_dest" --config "$config" --lang contract-tests-rust --out . +cargo fmt --all +echo "Generated Rust SDK and contract tests." + diff --git a/scripts/sdk-generator-config.json b/scripts/sdk-generator-config.json new file mode 100644 index 0000000..39f215f --- /dev/null +++ b/scripts/sdk-generator-config.json @@ -0,0 +1,9 @@ +{ + "name": "archastro", + "version": "0.1.0", + "baseUrl": "https://platform.archastro.ai", + "apiBase": "/api", + "defaultVersion": "v1", + "description": "Official Rust SDK for the ArchAstro Platform API" +} + diff --git a/specs/platform-openapi.json b/specs/platform-openapi.json new file mode 100644 index 0000000..ed1d9e8 --- /dev/null +++ b/specs/platform-openapi.json @@ -0,0 +1,113972 @@ +{ + "components": { + "schemas": { + "AIChatStreamDone": { + "description": "Terminal event marking the end of a streaming chat completion (SSE `done` event).", + "example": { + "finish_reason": "stop", + "run_count": 1, + "total_usage": {}, + "usage": {} + }, + "properties": { + "finish_reason": { + "description": "The overall finish reason for the completion.", + "example": "stop", + "type": "string" + }, + "run_count": { + "description": "Number of model runs executed, including continuations triggered by tool calls.", + "example": 1, + "type": "integer" + }, + "total_usage": { + "description": "Aggregate token usage across every run in the completion (including tool-call continuations), keyed by model ID.", + "example": {}, + "type": "object" + }, + "usage": { + "description": "Token usage for the final run, keyed by model ID.", + "example": {}, + "type": "object" + } + }, + "type": "object" + }, + "AIChatStreamError": { + "description": "Terminal error event for a streaming chat completion (SSE `error` event).", + "example": { + "message": "string" + }, + "properties": { + "message": { + "description": "Human-readable description of the error that terminated the stream.", + "example": "string", + "type": "string" + } + }, + "required": [ + "message" + ], + "type": "object" + }, + "AIChatStreamMessageComplete": { + "description": "The fully assembled assistant message for one run of a streaming chat completion (SSE `message_complete` event).", + "example": { + "finish_reason": "stop", + "message": { + "content": "How can I help you today?", + "content_parts": [ + {} + ], + "resume_token": "string", + "role": "user", + "tool_calls": [ + { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + } + ], + "tool_results": [ + { + "content": "string", + "id": "string", + "name": "Example Name" + } + ] + }, + "usage": {} + }, + "properties": { + "finish_reason": { + "description": "Why the model stopped generating this message, e.g. `\"stop\"`, `\"length\"`, or `\"tool_calls\"`.", + "example": "stop", + "type": "string" + }, + "message": { + "$ref": "#/components/schemas/AIMessage", + "description": "The complete assistant message for this run, assembled from the preceding deltas." + }, + "usage": { + "description": "Token consumption for this run, keyed by model ID. `null` when usage data is unavailable.", + "example": {}, + "type": "object" + } + }, + "required": [ + "message" + ], + "type": "object" + }, + "AIChatStreamMessageDelta": { + "description": "Incremental assistant text emitted during a streaming chat completion (SSE `message_delta` event).", + "example": { + "delta": "string" + }, + "properties": { + "delta": { + "description": "The chunk of assistant text produced since the previous `message_delta` event. Concatenate deltas in order to reconstruct the message.", + "example": "string", + "type": "string" + } + }, + "required": [ + "delta" + ], + "type": "object" + }, + "AIChatStreamThinkingDelta": { + "description": "Incremental model reasoning emitted during a streaming chat completion (SSE `thinking_delta` event).", + "example": { + "delta": "string" + }, + "properties": { + "delta": { + "description": "The chunk of model reasoning produced since the previous `thinking_delta` event.", + "example": "string", + "type": "string" + } + }, + "required": [ + "delta" + ], + "type": "object" + }, + "AIChatStreamToolCallDelta": { + "description": "Incremental tool-call data emitted as the model assembles a tool invocation (SSE `tool_call_delta` event).", + "example": { + "delta": "string", + "id": "string", + "name": "Example Name" + }, + "properties": { + "delta": { + "description": "A chunk of the tool call's serialized arguments. Concatenate deltas to reconstruct the arguments JSON.", + "example": "string", + "type": "string" + }, + "id": { + "description": "Identifier of the tool call this delta belongs to, once the model has assigned one.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Name of the tool being called, once known.", + "example": "Example Name", + "type": "string" + } + }, + "type": "object" + }, + "AIChatStreamToolResult": { + "description": "The result of a server-executed tool, streamed back into the run (SSE `tool_result` event).", + "example": { + "content": "string", + "id": "string", + "name": "Example Name", + "resolution": "string" + }, + "properties": { + "content": { + "description": "The tool's output, serialized as a string.", + "example": "string", + "type": "string" + }, + "id": { + "description": "ID of the tool call this result satisfies.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Name of the tool that produced this result.", + "example": "Example Name", + "type": "string" + }, + "resolution": { + "description": "How the tool call resolved, e.g. `\"ok\"` or `\"error\"`.", + "example": "string", + "type": "string" + } + }, + "type": "object" + }, + "AICompletionResult": { + "description": "The result of an AI chat completion request. Returned by chat completion endpoints after the model finishes generating.", + "example": { + "finish_reason": "stop", + "message": { + "content": "How can I help you today?", + "content_parts": [ + {} + ], + "resume_token": "string", + "role": "user", + "tool_calls": [ + { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + } + ], + "tool_results": [ + { + "content": "string", + "id": "string", + "name": "Example Name" + } + ] + }, + "messages": [ + { + "content": "How can I help you today?", + "content_parts": [ + {} + ], + "resume_token": "string", + "role": "user", + "tool_calls": [ + { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + } + ], + "tool_results": [ + { + "content": "string", + "id": "string", + "name": "Example Name" + } + ] + } + ], + "token_usage": {} + }, + "properties": { + "finish_reason": { + "description": "The reason the model stopped generating. Common values include `\"stop\"` (natural end), `\"length\"` (token limit reached), and `\"tool_calls\"` (the model invoked a tool).", + "example": "stop", + "type": "string" + }, + "message": { + "$ref": "#/components/schemas/AIMessage", + "description": "The final assistant message produced by the completion." + }, + "messages": { + "description": "The complete message history for the conversation, including all user, assistant, and tool messages in order.", + "items": { + "$ref": "#/components/schemas/AIMessage" + }, + "type": "array" + }, + "token_usage": { + "description": "Token consumption breakdown keyed by model ID. Each value is a map with `\"input_tokens\"` and `\"output_tokens\"` counts. `null` when usage data is unavailable.", + "example": {}, + "type": "object" + } + }, + "required": [ + "message", + "messages", + "finish_reason" + ], + "type": "object" + }, + "AIImageResult": { + "description": "The result returned by an AI image generation or editing operation. Contains the generated image (as inline data or a URL) along with dimension, size, and usage metadata.", + "example": { + "aspect_ratio": "1:1", + "height": 1024, + "image_data": "string", + "image_size": "1K", + "image_type": "image/png", + "image_url": "https://example.com", + "model": "dall-e-3", + "revised_prompt": "A photorealistic image of a sunset over the ocean with warm golden hues.", + "size": "1024x1024", + "usage": { + "key": "value" + }, + "width": 1024 + }, + "properties": { + "aspect_ratio": { + "description": "Aspect ratio of the generated image, e.g. `\"16:9\"` or `\"1:1\"`. `null` when not reported by the provider.", + "example": "1:1", + "type": "string" + }, + "height": { + "description": "Height of the generated image in pixels. `null` when the provider does not report dimensions.", + "example": 1024, + "type": "integer" + }, + "image_data": { + "description": "The generated image encoded as a base64 string. Present when the provider returns inline image data. `null` when `image_url` is set instead.", + "example": "string", + "type": "string" + }, + "image_size": { + "description": "Resolution tier label for the image, e.g. `\"1K\"` or `\"2K\"`. `null` when the provider does not include a tier label.", + "example": "1K", + "type": "string" + }, + "image_type": { + "description": "MIME type of the generated image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` when the provider does not report a content type.", + "example": "image/png", + "type": "string" + }, + "image_url": { + "description": "Temporary URL pointing to the generated image hosted by the provider. Present when the provider returns a URL rather than inline data. `null` when `image_data` is set instead.", + "example": "https://example.com", + "type": "string" + }, + "model": { + "description": "Identifier of the model that produced the image, e.g. `\"dall-e-3\"` or `\"imagen-3\"`.", + "example": "dall-e-3", + "type": "string" + }, + "revised_prompt": { + "description": "The prompt as rewritten by the provider before generation. Some providers (e.g. DALL-E 3) automatically expand or safety-check the original prompt. `null` when the provider does not revise prompts.", + "example": "A photorealistic image of a sunset over the ocean with warm golden hues.", + "type": "string" + }, + "size": { + "description": "Canonical size string as returned by the provider, e.g. `\"1024x1024\"`. `null` when not reported.", + "example": "1024x1024", + "type": "string" + }, + "usage": { + "description": "Provider-reported token and compute usage for the request. Structure varies by provider. `null` when usage data is unavailable.", + "example": { + "key": "value" + }, + "type": "object" + }, + "width": { + "description": "Width of the generated image in pixels. `null` when the provider does not report dimensions.", + "example": 1024, + "type": "integer" + } + }, + "required": [ + "model" + ], + "type": "object" + }, + "AIMessage": { + "description": "A single message in an AI conversation, following the OpenAI-compatible chat format. Used in both request inputs and completion responses.", + "example": { + "content": "How can I help you today?", + "content_parts": [ + {} + ], + "resume_token": "string", + "role": "user", + "tool_calls": [ + { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + } + ], + "tool_results": [ + { + "content": "string", + "id": "string", + "name": "Example Name" + } + ] + }, + "properties": { + "content": { + "description": "Plain-text content of the message. Present for `system`, `user`, and `assistant` messages. `null` when the message body is expressed through `content_parts` or `tool_calls`.", + "example": "How can I help you today?", + "type": "string" + }, + "content_parts": { + "description": "Multimodal content parts for the message, used when the body includes images or mixed media. Each part is a map with a `type` key (`\"text\"`, `\"image_url\"`, or `\"image_data\"`). `null` when `content` is set.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "resume_token": { + "description": "Opaque token that can be passed on a subsequent request to resume this conversation from the current state. `null` when the provider does not support conversation resumption.", + "example": "string", + "type": "string" + }, + "role": { + "description": "The speaker role for this message. One of `\"system\"`, `\"user\"`, `\"assistant\"`, or `\"tool\"`.", + "example": "user", + "type": "string" + }, + "structured_output": { + "description": "Parsed structured data returned by the model when a JSON schema or structured-output mode was requested. Shape varies by the schema supplied at call time. `null` when structured output was not requested." + }, + "tool_calls": { + "description": "Tool calls requested by the model in an `assistant` message. Present only on assistant messages that invoke one or more tools. `null` on all other message roles.", + "items": { + "$ref": "#/components/schemas/AIToolCall" + }, + "type": "array" + }, + "tool_results": { + "description": "Tool execution results provided in a `tool` message. Each entry corresponds to a prior tool call by its `id`. `null` on all other message roles.", + "items": { + "$ref": "#/components/schemas/AIToolResult" + }, + "type": "array" + } + }, + "required": [ + "role" + ], + "type": "object" + }, + "AIToolCall": { + "description": "A tool (function) call emitted by the assistant within an AI message. Mirrors the OpenAI tool-call object format.", + "example": { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + }, + "properties": { + "arguments": { + "description": "Arguments the model wants to pass to the tool, as a key-value map. Deserialize and validate these against the tool's input schema before executing.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Unique identifier for this tool call, assigned by the model. Use this value as `id` when submitting the corresponding tool result.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Name of the tool or function the model wants to invoke, e.g. `\"web_search\"` or `\"run_code\"`.", + "example": "Example Name", + "type": "string" + }, + "thought_signature": { + "description": "Opaque signature representing the model's internal reasoning that led to this tool call. `null` when the provider does not expose chain-of-thought data.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "name", + "arguments" + ], + "type": "object" + }, + "AIToolResult": { + "description": "The result of executing a tool call, submitted back to the model as a tool-role message. Mirrors the OpenAI tool-result object format.", + "example": { + "content": "string", + "id": "string", + "name": "Example Name" + }, + "properties": { + "content": { + "description": "Plain-text output produced by the tool execution. `null` when the result is expressed entirely through `resolution`.", + "example": "string", + "type": "string" + }, + "id": { + "description": "ID of the tool call this result satisfies. Must match the `id` from the corresponding `AIToolCall`.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Name of the tool or function that was executed, e.g. `\"web_search\"`. Must match the `name` from the corresponding `AIToolCall`.", + "example": "Example Name", + "type": "string" + }, + "resolution": { + "description": "Structured result data from the tool execution. Shape varies by tool. `null` when the result is expressed as plain text in `content`." + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "Acl": { + "description": "An access-control list payload that supports either full replacement or targeted patch operations on a resource's grants.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "items": { + "$ref": "#/components/schemas/AclGrant" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "items": { + "$ref": "#/components/schemas/AclGrant" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "items": { + "$ref": "#/components/schemas/AclRemoveTarget" + }, + "type": "array" + } + }, + "type": "object" + }, + "AclGrant": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "AclRemoveTarget": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "ActivityFeedEntry": { + "description": "A single event record in an activity feed, capturing what happened, who caused it, and which resources were involved.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "attachments": [ + {} + ], + "automation_run": "atr_0aBcDeFgHiJkLmNoPqRsTu", + "content": "The agent completed the task successfully.", + "correlation_id": "01234567-89ab-cdef-0123-456789abcdef", + "created_at": "2024-01-01T00:00:00Z", + "id": "afe_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_step", + "level": "info", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "routine_run": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "session_record": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "The agent that produced this event. Returns an agent ID (`agi_...`) by default, or an expanded agent object when the association is loaded. `null` if no agent is associated.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "oneOf": [ + { + "type": "string" + }, + { + "description": "An AI agent that can be configured with tools, routines, and skills, and invoked to handle conversations or tasks.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints.", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "solution": { + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + }, + "app": { + "description": "ID of the application that produced this entry (`dap_...`). `null` if not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "attachments": { + "description": "Array of attachment objects associated with this entry. Each attachment has a `type` field (e.g. `\"file\"`, `\"task\"`, `\"artifact\"`) and type-specific additional fields. Empty array when there are no attachments.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "automation_run": { + "description": "ID of the automation run that produced this entry (`atr_...`). `null` if not produced by an automation run.", + "example": "atr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "content": { + "description": "A longer explanation of the event rendered as Markdown. `null` if no additional content is available.", + "example": "The agent completed the task successfully.", + "type": "string" + }, + "correlation_id": { + "description": "An opaque string used to group related entries together. Entries sharing the same `correlation_id` belong to a single logical operation. `null` if not correlated.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "created_at": { + "description": "When this activity feed entry was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Activity feed entry ID (`afe_...`).", + "example": "afe_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "The type of event this entry represents, e.g. `\"agent_step\"` or `\"tool_call\"`. Determines how `title`, `content`, and `attachments` should be interpreted.", + "example": "agent_step", + "type": "string" + }, + "level": { + "description": "Severity level of the event. One of `\"info\"`, `\"warning\"`, or `\"error\"`. `null` if no severity is set.", + "example": "info", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata stored on this entry. Returns an empty object when no metadata is set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization this entry belongs to (`org_...`). `null` if not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "routine_run": { + "description": "ID of the agent routine run that produced this entry (`arr_...`). `null` if not produced by a routine run.", + "example": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Identifier of the sandbox environment this entry was generated in. `null` in production contexts.", + "example": "string", + "type": "string" + }, + "session_record": { + "description": "ID of the agent session record this entry belongs to (`ase_...`). `null` if not part of an agent session.", + "example": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "team": { + "description": "ID of the team this entry is associated with (`tem_...`). `null` if not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this entry is associated with (`thr_...`). `null` if not linked to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "title": { + "description": "A one-line human-readable summary of the event. `null` if the entry has no title.", + "example": "Example Title", + "type": "string" + }, + "updated_at": { + "description": "When this activity feed entry was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "The user who triggered this event. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if no user is associated.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "oneOf": [ + { + "type": "string" + }, + { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "ActivityFeedEntryListResponse": { + "description": "A paginated list of activity feed entries returned by a feed query, with cursors for navigating backward and forward through results.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "entries": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "attachments": [ + {} + ], + "automation_run": "atr_0aBcDeFgHiJkLmNoPqRsTu", + "content": "The agent completed the task successfully.", + "correlation_id": "01234567-89ab-cdef-0123-456789abcdef", + "created_at": "2024-01-01T00:00:00Z", + "id": "afe_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_step", + "level": "info", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "routine_run": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "session_record": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor to pass as `after` to retrieve the next page of entries. `null` when this is the last page.", + "example": "string", + "type": "string" + }, + "before_cursor": { + "description": "Opaque cursor to pass as `before` to retrieve the previous page of entries. `null` when this is the first page.", + "example": "string", + "type": "string" + }, + "entries": { + "description": "Array of activity feed entry objects for the current page, ordered by time descending.", + "items": { + "$ref": "#/components/schemas/ActivityFeedEntry" + }, + "type": "array" + }, + "has_more": { + "description": "Whether additional entries exist beyond the current page. When `true`, use `after_cursor` to fetch the next page.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "entries", + "has_more" + ], + "type": "object" + }, + "Actor": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "$ref": "#/components/schemas/ImageSource", + "description": "Profile picture for the actor. `null` if the actor has no profile picture." + } + }, + "type": "object" + }, + "Agent": { + "description": "An AI agent that can be configured with tools, routines, and skills, and invoked to handle conversations or tasks.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "$ref": "#/components/schemas/Acl", + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope." + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "$ref": "#/components/schemas/AgentSourceSolution", + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints." + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "AgentComputer": { + "description": "A cloud computer resource provisioned for an agent to use for browser and desktop automation tasks.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "config": { + "key": "value" + }, + "created_at": "2024-01-01T00:00:00Z", + "error_message": "string", + "id": "cmp_0aBcDeFgHiJkLmNoPqRsTu", + "last_active_at": "2024-01-01T00:00:00Z", + "lookup_key": "main-computer", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "provider": "sprites", + "region": "us-east-1", + "sprite_url": "https://example.com", + "status": "ready", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this computer (`agi_...`). `null` if the computer is not yet assigned to an agent.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app": { + "description": "ID of the app this computer belongs to (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "config": { + "description": "Provider-specific configuration key-value pairs for the computer. Structure depends on the underlying compute provider.", + "example": { + "key": "value" + }, + "type": "object" + }, + "created_at": { + "description": "When the computer was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "error_message": { + "description": "Human-readable error description when `status` is `\"error\"`. `null` otherwise.", + "example": "string", + "type": "string" + }, + "id": { + "description": "Computer ID (`cmp_...`).", + "example": "cmp_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "last_active_at": { + "description": "When the computer last reported activity or received a command. `null` if the computer has never been active.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "lookup_key": { + "description": "Unique, stable identifier you assign to this computer within its app. `null` if not set.", + "example": "main-computer", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata you attached to the computer. `null` if none was provided.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the computer. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "provider": { + "description": "Compute backend powering this computer: `\"sprites\"` (Fly Sprites) or `\"vercel\"` (Vercel Sandbox).", + "example": "sprites", + "type": "string" + }, + "region": { + "description": "Cloud region where the computer is hosted, e.g. `\"us-east-1\"`. `null` if not yet assigned or when the provider has no region concept (e.g. `\"vercel\"`).", + "example": "us-east-1", + "type": "string" + }, + "sprite_url": { + "description": "URL of the live screenshot sprite used to render a real-time preview of the computer's screen. `null` when no sprite is available.", + "example": "https://example.com", + "type": "string" + }, + "status": { + "description": "Current lifecycle state of the computer. Common values include `\"provisioning\"`, `\"ready\"`, `\"error\"`, and `\"terminated\"`.", + "example": "ready", + "type": "string" + }, + "updated_at": { + "description": "When the computer record was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "AgentComputerListResponse": { + "description": "A list of agent computers returned by a list query.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "config": { + "key": "value" + }, + "created_at": "2024-01-01T00:00:00Z", + "error_message": "string", + "id": "cmp_0aBcDeFgHiJkLmNoPqRsTu", + "last_active_at": "2024-01-01T00:00:00Z", + "lookup_key": "main-computer", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "provider": "sprites", + "region": "us-east-1", + "sprite_url": "https://example.com", + "status": "ready", + "updated_at": "2024-01-01T00:00:00Z" + } + ] + }, + "properties": { + "data": { + "description": "Array of agent computer objects matching the query.", + "items": { + "$ref": "#/components/schemas/AgentComputer" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "AgentCreateResponse": { + "description": "The response returned by `POST /api/v1/agents`. Contains all agent fields plus an optional `installed_configs` array when a `template_bundle` was supplied in the request.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-5-sonnet-20241022", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant.", + "installed_configs": [ + { + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "my-skill", + "kind": "Skill", + "lookup_key": "my-skill" + } + ], + "lookup_key": "my-agent", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "originator": "my-service", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "$ref": "#/components/schemas/Acl", + "description": "Access control list governing who can interact with this agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied." + }, + "app": { + "description": "ID of the app this agent belongs to (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default AI model the agent uses when no model is specified at runtime, e.g. `\"claude-3-5-sonnet-20241022\"`. `null` if not configured.", + "example": "claude-3-5-sonnet-20241022", + "type": "string" + }, + "email": { + "description": "Email address assigned to this agent for inbound email handling. `null` if not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System prompt or persona description that shapes the agent's behavior. `null` if not set.", + "example": "You are a helpful assistant.", + "type": "string" + }, + "installed_configs": { + "description": "List of config records created as part of this request's `template_bundle` install. One entry per persisted config, sorted by `key`. Omitted entirely when the request did not include a `template_bundle`.", + "items": { + "$ref": "#/components/schemas/InstalledConfigEntry" + }, + "type": "array" + }, + "lookup_key": { + "description": "Unique, stable identifier for the agent within its app. `null` if not set.", + "example": "my-agent", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. `null` if none was provided.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` for agents outside an org.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author of the agent, e.g. a username or service name. `null` if not set.", + "example": "my-service", + "type": "string" + }, + "phone_number": { + "description": "Phone number assigned to this agent for inbound SMS or voice handling. `null` if not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`sbx_...`). `null` for agents not scoped to a sandbox.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this agent (`tea_...`). `null` if owned by a user rather than a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the agent record was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if owned by a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "AgentEnvVarMasked": { + "description": "An agent environment variable with its secret value masked for safe display in list and show responses.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "anv_0aBcDeFgHiJkLmNoPqRsTu", + "key": "OPENAI_API_KEY", + "masked_value": "****1234", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "agent": { + "description": "ID of the agent this environment variable belongs to (`agt_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the environment variable was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Optional human-readable note describing the purpose of this variable. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Environment variable ID (`anv_...`).", + "example": "anv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "key": { + "description": "Name of the environment variable as it appears in the agent's runtime.", + "example": "OPENAI_API_KEY", + "type": "string" + }, + "masked_value": { + "description": "Redacted representation of the secret value. The last four characters are preserved; all preceding characters are replaced with `****`. Returns `****` when the value is absent or four characters or fewer.", + "example": "****1234", + "type": "string" + }, + "updated_at": { + "description": "When the environment variable was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "agent", + "key", + "masked_value" + ], + "type": "object" + }, + "AgentEnvVarMaskedList": { + "description": "Flat list of masked environment variables belonging to an agent.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "anv_0aBcDeFgHiJkLmNoPqRsTu", + "key": "OPENAI_API_KEY", + "masked_value": "****1234", + "updated_at": "2024-01-01T00:00:00Z" + } + ] + }, + "properties": { + "data": { + "description": "Array of masked environment variable objects for the agent.", + "items": { + "$ref": "#/components/schemas/AgentEnvVarMasked" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "AgentExport": { + "description": "A portable export bundle for an agent, containing everything needed to re-deploy it in another workspace or environment.", + "example": { + "configs": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "current_version": { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + }, + "id": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "is_archived": true, + "kind": "Agent", + "lookup_key": "string", + "mime_type": "application/json", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "parent_solution": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "raw_content": "string", + "relative_path": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "virtual_path": "agents/my-agent.yaml" + } + ], + "template": {} + }, + "properties": { + "configs": { + "description": "Ordered list of config file objects that the agent depends on. Included in full so the import can recreate all dependencies without additional requests.", + "items": { + "$ref": "#/components/schemas/Config" + }, + "type": "array" + }, + "template": { + "description": "The agent template definition as a structured map. Pass this directly to the import endpoint to recreate the agent.", + "example": {}, + "type": "object" + } + }, + "required": [ + "template", + "configs" + ], + "type": "object" + }, + "AgentHealth": { + "description": "Aggregate health profile for an agent, summarizing its current operational status, score, and the full list of setup and health actions.", + "example": { + "activity": {}, + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "checked_at": "2024-01-01T00:00:00Z", + "checks": [ + {} + ], + "counts": {}, + "health_actions": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "depends_on": [ + "string" + ], + "description": "An example description.", + "id": "aha_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "env_var", + "last_verified_at": "2024-01-01T00:00:00Z", + "last_verifier_message": "string", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "source": "setup", + "status": "pending", + "title": "Example Title", + "updated_at": "2024-01-01T00:00:00Z", + "verify_config": {} + } + ], + "recent": {}, + "score": 85, + "status": "ok" + }, + "properties": { + "activity": { + "description": "Timestamps for the agent's most recent and next scheduled activity, used to surface last-run and upcoming-run information.", + "example": {}, + "type": "object" + }, + "agent": { + "$ref": "#/components/schemas/Agent", + "description": "The agent this health profile describes." + }, + "checked_at": { + "description": "When the health profile was last computed (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "checks": { + "description": "Renderable health check results. Each object includes at minimum `key`, `label`, `status`, and `summary` fields.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "counts": { + "description": "Action counts broken down by dependency area and resolution status, used to render progress indicators per category.", + "example": {}, + "type": "object" + }, + "health_actions": { + "description": "All actionable items tracked for this agent, including both `\"setup\"` items (post-install checklist) and `\"health\"` items (probe-detected issues). Sorted by `(source, sort_order, id)`. Use each item's `params` field to construct deep-links that route the user to the correct resolution flow.", + "items": { + "$ref": "#/components/schemas/AgentHealthAction" + }, + "type": "array" + }, + "recent": { + "description": "Recent execution metrics for the agent, including run counts and failure counts over a recent time window.", + "example": {}, + "type": "object" + }, + "score": { + "description": "Normalized health score from `0` (fully degraded) to `100` (fully healthy), derived from the weight and status of all health actions.", + "example": 85, + "type": "integer" + }, + "status": { + "description": "Overall health status of the agent. One of `\"ok\"`, `\"warning\"`, or `\"critical\"`.", + "example": "ok", + "type": "string" + } + }, + "required": [ + "agent", + "checked_at", + "status", + "score", + "counts", + "recent", + "activity", + "checks", + "health_actions" + ], + "type": "object" + }, + "AgentHealthAction": { + "description": "A single actionable item in an agent's health or setup checklist, carrying the structured data needed to render the item and deep-link to the resolution flow.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "depends_on": [ + "string" + ], + "description": "An example description.", + "id": "aha_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "env_var", + "last_verified_at": "2024-01-01T00:00:00Z", + "last_verifier_message": "string", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "source": "setup", + "status": "pending", + "title": "Example Title", + "updated_at": "2024-01-01T00:00:00Z", + "verify_config": {} + }, + "properties": { + "agent": { + "description": "ID of the agent this action is scoped to (`agt_...`). `null` for org-level actions.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app": { + "description": "ID of the application this action is associated with (`app_...`). `null` when not app-scoped.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When this health action was first created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "depends_on": { + "description": "IDs of other health actions that must reach `\"completed\"` status before this action can be started. Empty array when there are no dependencies.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "description": { + "description": "Longer Markdown-formatted explanation of what the action requires and why. `null` if not provided.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Health action ID (`aha_...`).", + "example": "aha_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Category of action to take. One of `\"env_var\"` (set a secret), `\"install\"` (complete an agent installation, e.g. a GitHub App), `\"custom\"` (agent-defined step), or `\"integration\"` (authorize an OAuth-backed MCP server integration).", + "example": "env_var", + "type": "string" + }, + "last_verified_at": { + "description": "When the verifier last ran for this action (ISO 8601). `null` until the verifier has been invoked at least once.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "last_verifier_message": { + "description": "Human-readable output from the most recent verifier run. `null` if the verifier has not run yet.", + "example": "string", + "type": "string" + }, + "org": { + "description": "ID of the organization this action is associated with (`org_...`). `null` when not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "params": { + "description": "Kind-specific structured data used to construct the deep-link for this action. For `\"env_var\"` actions includes `key` and `scope`; for `\"install\"` actions includes `installation_kind`; for `\"integration\"` actions includes `mcp_server_ref`, and when resolvable also includes `provider`, `integration_id` for OAuth handoff, and `connection_status` (`\"connected\"`, `\"disconnected\"`, or `\"token_expired\"`). Empty object `{}` when no additional parameters are needed.", + "example": { + "key": "value" + }, + "type": "object" + }, + "required": { + "description": "`true` if this action must be completed before the agent is considered fully operational and counts toward the blocking checklist progress bar.", + "example": true, + "type": "boolean" + }, + "sort_order": { + "description": "Display order within the same `source` group. Lower values appear first.", + "example": 1, + "type": "integer" + }, + "source": { + "description": "Lifecycle stage that produced this action. One of `\"setup\"` (post-install checklist item) or `\"health\"` (probe-detected issue).", + "example": "setup", + "type": "string" + }, + "status": { + "description": "Current resolution state. One of `\"pending\"` (not yet completed), `\"completed\"` (resolved), `\"skipped\"` (dismissed by the user), or `\"degraded\"` (completed but the verifier is reporting a warning).", + "example": "pending", + "type": "string" + }, + "title": { + "description": "Short display label for this action, intended for use as a checklist item heading.", + "example": "Example Title", + "type": "string" + }, + "updated_at": { + "description": "When this health action was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "verify_config": { + "description": "Configuration for the action's verifier step. Contains at minimum a `type` field that indicates which verification affordance to render. Server-internal fields are stripped before this is returned.", + "example": {}, + "type": "object" + } + }, + "required": [ + "id", + "source", + "kind", + "status", + "title", + "required", + "sort_order" + ], + "type": "object" + }, + "AgentListResponse": { + "description": "Paginated list of agent objects. Use the pagination fields to traverse multiple pages of results.", + "example": { + "data": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 20, + "total_entries": 42, + "total_pages": 1 + }, + "properties": { + "data": { + "description": "Array of agent objects for the current page.", + "items": { + "$ref": "#/components/schemas/Agent" + }, + "type": "array" + }, + "has_next": { + "description": "`true` when a subsequent page of results exists.", + "example": true, + "type": "boolean" + }, + "has_prev": { + "description": "`true` when a previous page of results exists.", + "example": true, + "type": "boolean" + }, + "page": { + "description": "Current page number, starting at 1.", + "example": 1, + "type": "integer" + }, + "page_size": { + "description": "Maximum number of agents returned per page.", + "example": 20, + "type": "integer" + }, + "total_entries": { + "description": "Total number of agents matching the query across all pages.", + "example": 42, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages available given the current `page_size`.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "AgentRoutine": { + "description": "An agent routine defines a reusable handler — script, preset, or chain — that runs in response to events or on a schedule.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "event_config": {}, + "event_type": "agentroutine.invoked", + "handler_type": "script", + "id": "arn_0aBcDeFgHiJkLmNoPqRsTu", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "daily-digest", + "message_policy": { + "recipients": [ + "routine_owner", + "run_actor" + ], + "visibility": "private" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "preset_config": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "preset_name": "Example Name", + "schedule": "string", + "script": "string", + "status": "active", + "steps": [ + {} + ], + "trigger_context": "event", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "$ref": "#/components/schemas/Acl", + "description": "Access control list for the routine. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions` (`\"read\"`, `\"invoke\"`, or `\"assign\"` — an `\"assign\"` grant names the agents or orgs that may be handed this routine's embedded work items). `null` when no ACL restrictions are applied and the routine is accessible to all members of its scope." + }, + "agent": { + "description": "ID of the agent that owns this routine (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app": { + "description": "Application that scopes this routine (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "config": { + "description": "ID of the Config record that backs this routine's configuration (`cfg_...`). `null` when the routine is not config-backed.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When this routine was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Optional description of what this routine does. `null` when not set.", + "example": "An example description.", + "type": "string" + }, + "event_config": { + "description": "Additional configuration controlling how the event trigger is matched or filtered. Shape depends on `event_type`. `null` when not configured.", + "example": {}, + "type": "object" + }, + "event_type": { + "description": "Platform event type that triggers this routine, e.g. `\"agentroutine.invoked\"`. `null` for schedule-only routines.", + "example": "agentroutine.invoked", + "type": "string" + }, + "handler_type": { + "description": "Execution strategy for this routine. One of `\"workflow_graph\"`, `\"script\"`, `\"preset\"`, or `\"chain\"`.", + "example": "script", + "type": "string" + }, + "id": { + "description": "Routine ID (`arn_...`).", + "example": "arn_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentRoutineTemplate Config this routine was last provisioned or updated from (`cfg_...`). `null` for hand-built routines.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Unique human-readable key used to look up this routine without knowing its ID. `null` when not set.", + "example": "daily-digest", + "type": "string" + }, + "message_policy": { + "$ref": "#/components/schemas/MessagePolicy", + "description": "Visibility and explicit recipient selection for messages emitted by this routine." + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this routine. `null` when not set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable name for the routine.", + "example": "Example Name", + "type": "string" + }, + "preset_config": { + "$ref": "#/components/schemas/PresetConfig", + "description": "Resolved preset configuration when `handler_type` is `\"preset\"`. `null` for other handler types." + }, + "preset_name": { + "description": "Name of the preset invoked when `handler_type` is `\"preset\"`. `null` for other handler types.", + "example": "Example Name", + "type": "string" + }, + "schedule": { + "description": "Cron expression controlling when the routine fires on a schedule. `null` for event-only routines.", + "example": "string", + "type": "string" + }, + "script": { + "description": "Inline script body executed when `handler_type` is `\"script\"`. `null` for other handler types.", + "example": "string", + "type": "string" + }, + "status": { + "description": "Lifecycle status of the routine. One of `\"draft\"`, `\"active\"`, or `\"paused\"`. Only `\"active\"` routines respond to triggers.", + "example": "active", + "type": "string" + }, + "steps": { + "description": "Ordered list of chain steps (present when handler_type is \"chain\"). Each step is a plain map with handler_type, optional body fields (preset_name / preset_config / script / config), and step-local plumbing (name, inputs, output_key, on_error).", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "trigger_context": { + "description": "Execution context in which runs are created. One of `\"event\"` (background job) or `\"chat_session\"` (interactive session). Defaults to `\"event\"`.", + "example": "event", + "type": "string" + }, + "updated_at": { + "description": "When this routine was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "Optional co-owner user (`usr_...`). When set, that user shares view/modify/delete authority on this routine without administering the parent agent. `null` when not set. Never inferred from the caller — only present when explicitly provided on create/update.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "AgentRoutineListResponse": { + "description": "List of agent routine objects belonging to a given agent.", + "example": { + "data": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "event_config": {}, + "event_type": "agentroutine.invoked", + "handler_type": "script", + "id": "arn_0aBcDeFgHiJkLmNoPqRsTu", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "daily-digest", + "message_policy": { + "recipients": [ + "routine_owner", + "run_actor" + ], + "visibility": "private" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "preset_config": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "preset_name": "Example Name", + "schedule": "string", + "script": "string", + "status": "active", + "steps": [ + {} + ], + "trigger_context": "event", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ] + }, + "properties": { + "data": { + "description": "Array of agent routine objects.", + "items": { + "$ref": "#/components/schemas/AgentRoutine" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "AgentRoutineRun": { + "description": "A single execution of an agent routine, capturing its status, inputs, outputs, and timing.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "delivery": { + "delivered_at": "2024-01-01T00:00:00Z", + "delivered_message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "last_error": "string", + "message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "status": "not_requested", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "none" + }, + "duration_ms": 1250, + "event_id": "string", + "id": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "participants": {}, + "payload": {}, + "result": {}, + "routine": "arn_0aBcDeFgHiJkLmNoPqRsTu", + "status": "completed", + "structured_response": {}, + "updated_at": "2024-01-01T00:00:00Z", + "worker": { + "attempt": 1, + "max_attempts": 3, + "status": "executing" + } + }, + "properties": { + "acl": { + "$ref": "#/components/schemas/Acl", + "description": "Access control list for the run. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the run is accessible to all members of its scope." + }, + "agent": { + "description": "ID of the agent that owns the parent routine (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app": { + "description": "Application that scopes this run (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When this run was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "delivery": { + "$ref": "#/components/schemas/AgentRoutineRunDelivery", + "description": "Normalized final-result delivery destination and its current delivery status." + }, + "duration_ms": { + "description": "Total wall-clock time the run took to execute, in milliseconds. `null` while the run is still in progress.", + "example": 1250, + "type": "integer" + }, + "event_id": { + "description": "Identifier of the platform event that triggered this run. `null` for manually invoked runs.", + "example": "string", + "type": "string" + }, + "id": { + "description": "Routine run ID (`arr_...`).", + "example": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this run. Empty object when no metadata was set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "participants": { + "description": "Invoke-time map of symbolic participant references to agent IDs. `null` when no participants were supplied.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Input payload delivered to the routine when this run was triggered. Empty object when no payload was provided.", + "example": {}, + "type": "object" + }, + "result": { + "description": "Output produced by the routine after execution. `null` while the run has not yet completed.", + "example": {}, + "type": "object" + }, + "routine": { + "description": "ID of the parent routine that produced this run (`arn_...`).", + "example": "arn_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current execution status. One of `\"pending\"`, `\"running\"`, `\"completed\"`, `\"failed\"`, `\"skipped\"`, or `\"cancelled\"`.", + "example": "completed", + "type": "string" + }, + "structured_response": { + "description": "Validated structured output extracted from `result` when the routine uses an AgentMessageSchema. `null` if the routine does not use a schema or the run has not completed.", + "example": {}, + "type": "object" + }, + "updated_at": { + "description": "When this run was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "worker": { + "$ref": "#/components/schemas/WorkerStatus", + "description": "Background worker status. `null` when no worker job is associated with this run." + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "AgentRoutineRunDelivery": { + "description": "Normalized destination and status for an agent routine run's final-result delivery.", + "example": { + "delivered_at": "2024-01-01T00:00:00Z", + "delivered_message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "last_error": "string", + "message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "status": "not_requested", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "none" + }, + "properties": { + "delivered_at": { + "description": "When delivery completed successfully (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "delivered_message": { + "description": "ID of the message created by a successful delivery (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "last_error": { + "description": "Stable public error code for the most recent failed delivery attempt.", + "example": "string", + "type": "string" + }, + "message": { + "description": "Source message ID (`msg_...`) when the delivery is a reply.", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current delivery lifecycle status.", + "enum": [ + "not_requested", + "pending", + "delivered", + "failed" + ], + "example": "not_requested", + "type": "string" + }, + "thread": { + "description": "Destination thread ID (`thr_...`) when delivery was requested.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "type": { + "description": "Normalized delivery mode.", + "enum": [ + "none", + "thread", + "reply" + ], + "example": "none", + "type": "string" + } + }, + "required": [ + "type", + "status" + ], + "type": "object" + }, + "AgentRoutineRunListResponse": { + "description": "Cursor-paginated list of agent routine run objects, ordered by creation time descending.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "delivery": { + "delivered_at": "2024-01-01T00:00:00Z", + "delivered_message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "last_error": "string", + "message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "status": "not_requested", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "none" + }, + "duration_ms": 1250, + "event_id": "string", + "id": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "participants": {}, + "payload": {}, + "result": {}, + "routine": "arn_0aBcDeFgHiJkLmNoPqRsTu", + "status": "completed", + "structured_response": {}, + "updated_at": "2024-01-01T00:00:00Z", + "worker": { + "attempt": 1, + "max_attempts": 3, + "status": "executing" + } + } + ] + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor to pass as the after-cursor parameter to fetch the next page of runs. `null` when no later results exist.", + "example": "string", + "type": "string" + }, + "before_cursor": { + "description": "Opaque cursor to pass as the before-cursor parameter to fetch the page of runs that precede this one. `null` when no earlier results exist.", + "example": "string", + "type": "string" + }, + "data": { + "description": "Array of agent routine run objects for the current page.", + "items": { + "$ref": "#/components/schemas/AgentRoutineRun" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "AgentSchedule": { + "description": "A scheduled task created by an agent. Supports one-time and recurring (cron-based) execution patterns.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "cron_expression": "0 9 * * 1", + "id": "asc_0aBcDeFgHiJkLmNoPqRsTu", + "instructions": "Send a daily summary of open support tickets to the team Slack channel.", + "last_run_at": "2024-01-01T00:00:00Z", + "max_runs": 10, + "metadata": { + "key": "value" + }, + "next_run_at": "2024-01-01T00:00:00Z", + "run_count": 1, + "schedule_type": "recurring", + "scheduled_at": "2024-01-01T00:00:00Z", + "status": "active", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "timezone": "America/New_York", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this schedule (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app": { + "description": "ID of the application the schedule belongs to (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the schedule was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "cron_expression": { + "description": "Standard cron expression defining the recurrence pattern (e.g. `\"0 9 * * 1\"`). Present only when `schedule_type` is `\"recurring\"`. `null` for one-time schedules.", + "example": "0 9 * * 1", + "type": "string" + }, + "id": { + "description": "Schedule ID (`asc_...`).", + "example": "asc_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "instructions": { + "description": "The task description the agent will execute when this schedule fires.", + "example": "Send a daily summary of open support tickets to the team Slack channel.", + "type": "string" + }, + "last_run_at": { + "description": "UTC datetime of the most recent successful execution. `null` if the schedule has never run.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "max_runs": { + "description": "Maximum number of times a recurring schedule may fire before automatically transitioning to `\"completed\"`. `null` means no limit.", + "example": 10, + "type": "integer" + }, + "metadata": { + "description": "Arbitrary key-value pairs attached to the schedule by the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "next_run_at": { + "description": "UTC datetime of the next planned execution. `null` if the schedule has completed, been cancelled, or has not yet been computed.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "run_count": { + "description": "Total number of times this schedule has fired.", + "example": 1, + "type": "integer" + }, + "schedule_type": { + "description": "Determines how the schedule repeats. `\"once\"` fires a single time at `scheduled_at` then transitions to `\"completed\"`. `\"recurring\"` fires on the `cron_expression` and reschedules automatically.", + "example": "recurring", + "type": "string" + }, + "scheduled_at": { + "description": "The exact UTC datetime at which a one-time schedule fires. Present only when `schedule_type` is `\"once\"`. `null` for recurring schedules.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "status": { + "description": "Current lifecycle status of the schedule. One of `\"active\"` (will fire as planned), `\"paused\"` (temporarily suspended), `\"completed\"` (has run its last execution), `\"cancelled\"` (manually stopped), or `\"expired\"` (past its valid window).", + "example": "active", + "type": "string" + }, + "thread": { + "description": "Thread ID (`thr_...`) this schedule is bound to. When set, the scheduled task is delivered into the thread rather than creating a new session. `null` for session-based schedules.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "timezone": { + "description": "IANA timezone name used to interpret the cron expression or `scheduled_at` (e.g. `\"America/New_York\"`). Defaults to `\"Etc/UTC\"`.", + "example": "America/New_York", + "type": "string" + }, + "updated_at": { + "description": "When the schedule was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "AgentSession": { + "description": "A durable agent session record representing a single AI task execution. Tracks status, trajectory, result, and any inbox messages delivered to the session.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "completed_at": "2024-01-01T00:00:00Z", + "created_at": "2024-01-01T00:00:00Z", + "error": "string", + "id": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "inbox": [ + {} + ], + "instructions": "Summarize the latest activity report and post the results to Slack.", + "is_system_session": true, + "max_runs_per_turn": 25, + "max_tokens": 20000, + "max_turns": 100, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "result": {}, + "started_at": "2024-01-01T00:00:00Z", + "status": "running", + "trajectory": "trj_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this session (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "completed_at": { + "description": "When the session reached a terminal state (`\"completed\"`, `\"failed\"`, or `\"cancelled\"`). `null` if still in progress.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_at": { + "description": "When the session was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "error": { + "description": "Human-readable error message describing why the session failed. `null` unless `status` is `\"failed\"`.", + "example": "string", + "type": "string" + }, + "id": { + "description": "Session ID (`ase_...`).", + "example": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "inbox": { + "description": "Ordered list of messages delivered to the session's inbox while it was in the `\"waiting\"` state. Each entry includes `id`, `role`, `content`, `sender_id`, `sender_type`, `sent_at`, and `metadata`.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "instructions": { + "description": "The task the agent is instructed to perform in this session.", + "example": "Summarize the latest activity report and post the results to Slack.", + "type": "string" + }, + "is_system_session": { + "description": "`true` if this session was created by the platform internally (e.g. by a schedule or health action) rather than by a user or API caller.", + "example": true, + "type": "boolean" + }, + "max_runs_per_turn": { + "description": "Maximum number of tool calls the agent may make within a single turn. Defaults to `25`.", + "example": 25, + "type": "integer" + }, + "max_tokens": { + "description": "Maximum number of tokens the session may consume across all turns before being terminated. Defaults to `20000`.", + "example": 20000, + "type": "integer" + }, + "max_turns": { + "description": "Maximum number of agent turns (LLM calls) allowed before the session is forcibly terminated. Defaults to `100`.", + "example": 100, + "type": "integer" + }, + "metadata": { + "description": "Arbitrary key-value pairs attached to the session. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Optional human-readable label for the session. `null` when not set.", + "example": "Example Name", + "type": "string" + }, + "result": { + "description": "Structured output produced by the session on successful completion. Shape is agent-defined. `null` while the session is still running or if it failed.", + "example": {}, + "type": "object" + }, + "started_at": { + "description": "When the session began executing. `null` if still `\"pending\"`.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "status": { + "description": "Current execution status. One of `\"pending\"` (queued, not yet started), `\"running\"` (actively executing), `\"waiting\"` (paused for an inbox message or external event), `\"completed\"` (finished successfully), `\"failed\"` (terminated with an error), or `\"cancelled\"` (manually stopped).", + "example": "running", + "type": "string" + }, + "trajectory": { + "description": "ID of the trajectory that records the full message history for this session (`trj_...`). `null` until the session has started.", + "example": "trj_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "AgentSessionListResponse": { + "description": "Paginated list response containing an array of agent session objects.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "completed_at": "2024-01-01T00:00:00Z", + "created_at": "2024-01-01T00:00:00Z", + "error": "string", + "id": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "inbox": [ + {} + ], + "instructions": "Summarize the latest activity report and post the results to Slack.", + "is_system_session": true, + "max_runs_per_turn": 25, + "max_tokens": 20000, + "max_turns": 100, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "result": {}, + "started_at": "2024-01-01T00:00:00Z", + "status": "running", + "trajectory": "trj_0aBcDeFgHiJkLmNoPqRsTu" + } + ] + }, + "properties": { + "data": { + "description": "Array of agent session objects for the current page.", + "items": { + "$ref": "#/components/schemas/AgentSession" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "AgentSkill": { + "description": "A skill enabled on an agent, linking the agent to a skill configuration. Controls which capabilities the agent has access to.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "id": "ask_0aBcDeFgHiJkLmNoPqRsTu", + "instruction": "string", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "status": "active", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "agent": { + "description": "ID of the agent this skill is attached to (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app": { + "description": "ID of the application this skill belongs to (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "config": { + "description": "ID of the root skill config record that defines this skill's behavior (`cfg_...`).", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the skill was added to the agent (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Skill ID (`ask_...`).", + "example": "ask_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "instruction": { + "description": "Optional instruction text that overrides the default skill instructions for this specific agent. `null` when no override is set.", + "example": "string", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the agent template config from which this skill was last provisioned or updated (`cfg_...`). `null` if the skill was not provisioned from a template.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value pairs attached to the skill. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "status": { + "description": "Whether the skill is currently in use. `\"active\"` means the agent will use this skill during sessions. `\"inactive\"` means it is disabled but not deleted.", + "example": "active", + "type": "string" + }, + "updated_at": { + "description": "When the skill was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "AgentSkillList": { + "description": "Paginated list response containing an array of agent skill objects.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "id": "ask_0aBcDeFgHiJkLmNoPqRsTu", + "instruction": "string", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "status": "active", + "updated_at": "2024-01-01T00:00:00Z" + } + ] + }, + "properties": { + "data": { + "description": "Array of agent skill objects for the current page.", + "items": { + "$ref": "#/components/schemas/AgentSkill" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "AgentSourceSolution": { + "description": "Summary of the Solution and AgentTemplate that an agent was last provisioned from.\nReturned on single-agent responses; `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted.\n", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "$ref": "#/components/schemas/SolutionSummary", + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now." + }, + "solution": { + "$ref": "#/components/schemas/SolutionSummary", + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution." + }, + "template": { + "$ref": "#/components/schemas/UpgradeTemplateSummary", + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from." + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "AgentTool": { + "description": "A tool attached to an agent, defining a capability the agent can invoke during a conversation or task run.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "async": true, + "builtin_tool_config": {}, + "builtin_tool_key": "string", + "config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "handler_type": "http", + "id": "atl_0aBcDeFgHiJkLmNoPqRsTu", + "instruction": "string", + "kind": "builtin", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "name_prefix": "string", + "parameters": {}, + "parameters_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "status": "active", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "agent": { + "description": "ID of the agent this tool belongs to (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app": { + "description": "ID of the application that owns this tool (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "async": { + "description": "`true` when the tool executes asynchronously and returns a task handle rather than an immediate result.", + "example": true, + "type": "boolean" + }, + "builtin_tool_config": { + "description": "Provider-specific configuration for the built-in tool. Present only when `kind` is `\"builtin\"`. Shape varies by `builtin_tool_key`.", + "example": {}, + "type": "object" + }, + "builtin_tool_key": { + "description": "Registry key identifying the built-in tool implementation. Present only when `kind` is `\"builtin\"`.", + "example": "string", + "type": "string" + }, + "config": { + "description": "ID of the config record (`cfg_...`) containing this tool's full configuration. `null` for inline-only tools.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the tool was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of what the tool does, passed to the LLM as part of the tool definition. Resolved from the built-in registry for `kind: \"builtin\"` tools.", + "example": "An example description.", + "type": "string" + }, + "handler_type": { + "description": "Execution handler type. One of `\"http\"`, `\"script\"`, or `\"builtin\"`.", + "example": "http", + "type": "string" + }, + "id": { + "description": "Tool ID (`atl_...`).", + "example": "atl_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "instruction": { + "description": "Optional system-level instruction appended to the agent prompt when this tool is active.", + "example": "string", + "type": "string" + }, + "kind": { + "description": "Tool kind. One of `\"builtin\"`, `\"custom\"`, or `\"mcp\"`.", + "example": "builtin", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentToolTemplate config (`cfg_...`) this tool was last provisioned or updated from. `null` for manually created tools.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this tool within the agent. Unique per agent.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the tool. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable name of the tool as exposed to the LLM. Resolved from the built-in registry for `kind: \"builtin\"` tools.", + "example": "Example Name", + "type": "string" + }, + "name_prefix": { + "description": "Per-instance namespace prepended to LLM-facing tool names for built-in tools that support multiple instances per agent. `null` when not applicable.", + "example": "string", + "type": "string" + }, + "parameters": { + "description": "JSON Schema object describing the tool's input parameters as presented to the LLM.", + "example": {}, + "type": "object" + }, + "parameters_config": { + "description": "ID of the config record (`cfg_...`) storing the tool's parameter schema. `null` when parameters are defined inline.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the tool. One of `\"active\"` or `\"disabled\"`.", + "example": "active", + "type": "string" + }, + "updated_at": { + "description": "When the tool was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "AgentToolListResponse": { + "description": "Paginated list response containing the tools attached to an agent.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "async": true, + "builtin_tool_config": {}, + "builtin_tool_key": "string", + "config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "handler_type": "http", + "id": "atl_0aBcDeFgHiJkLmNoPqRsTu", + "instruction": "string", + "kind": "builtin", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "name_prefix": "string", + "parameters": {}, + "parameters_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "status": "active", + "updated_at": "2024-01-01T00:00:00Z" + } + ] + }, + "properties": { + "data": { + "description": "Array of agent tool objects returned for the current request.", + "items": { + "$ref": "#/components/schemas/AgentTool" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "AgentUpgradeChange": { + "description": "One child-resource change produced by an agent upgrade, describing the action to be taken on a single resource.", + "example": { + "action": "update", + "description": "An example description.", + "field_changes": [ + { + "field": "name", + "locally_edited": true + } + ], + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "string", + "name": "Example Name", + "parent_template_config": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "resource": {}, + "resource_type": "tool", + "source_template_config": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "action": { + "description": "The operation that will be performed. One of `\"add\"`, `\"update\"`, `\"remove\"`, or `\"noop\"`.", + "example": "update", + "type": "string" + }, + "description": { + "description": "Description of the child resource this change touches, when one is set. `null` when no description is available.", + "example": "An example description.", + "type": "string" + }, + "field_changes": { + "description": "Field-level diff entries for this change. Populated only when `action` is `\"update\"`; empty or absent for `add`, `remove`, and `noop` entries.", + "items": { + "$ref": "#/components/schemas/AgentUpgradeFieldChange" + }, + "type": "array" + }, + "id": { + "description": "Public ID of the existing resource being updated or removed (e.g. `atl_...`, `arn_...`). `null` for `add` entries.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "key": { + "description": "Lookup key of the resource derived from its source template. `null` when the template has no lookup key.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Human-facing name of the child resource this change touches (tool/routine/skill/computer name, or builtin tool key for unnamed builtin tools). Falls back to the source template's name. `null` for the synthetic `agent_base` entry.", + "example": "Example Name", + "type": "string" + }, + "parent_template_config": { + "$ref": "#/components/schemas/UpgradeTemplateSummary", + "description": "Summary of the parent AgentTemplate config (`cfg_...`) being applied in this upgrade." + }, + "resource": { + "description": "Resource-type-specific identity details. Tools: `tool_type`, `builtin_tool_key`, `name_prefix`, `handler_type`, `instruction`. Routines: `handler_type`, `preset_name`, `event_type`, `schedule`, `trigger_context`. Skills: `instruction`. Computers: `region`. Only populated keys are present; `null` when nothing is known.", + "example": {}, + "type": "object" + }, + "resource_type": { + "description": "Type of the child resource being changed. One of `\"agent\"`, `\"tool\"`, `\"routine\"`, `\"skill\"`, or `\"computer\"`.", + "example": "tool", + "type": "string" + }, + "source_template_config": { + "$ref": "#/components/schemas/UpgradeTemplateSummary", + "description": "Summary of the specific child template config (`cfg_...`) that defines this resource. `null` when no source template is resolvable." + } + }, + "required": [ + "resource_type", + "action", + "parent_template_config" + ], + "type": "object" + }, + "AgentUpgradeFieldChange": { + "description": "One field-level diff entry within an agent upgrade change, describing how a single field will change.\n`baseline` and `locally_edited` are populated only for `agent_base` entries; child resource entries (tools, routines, skills, computers) carry only `field`, `old`, and `new`.\n", + "example": { + "field": "name", + "locally_edited": true + }, + "properties": { + "baseline": { + "description": "Value that was set by the last-applied template version (pinned baseline). Populated only on `agent_base` field changes. `null` when no baseline is available (legacy agent or deleted version)." + }, + "field": { + "description": "Name of the field that will change, e.g. `\"name\"` or `\"identity\"`.", + "example": "name", + "type": "string" + }, + "locally_edited": { + "description": "`true` when the agent's current value differs from `baseline`, indicating a local edit that this upgrade will overwrite. `false` when the current value matches the baseline. `null` when `baseline` is unavailable. Populated only on `agent_base` field changes.", + "example": true, + "type": "boolean" + }, + "new": { + "description": "Incoming value the field will be set to after the upgrade (string, number, boolean, or `null`)." + }, + "old": { + "description": "Current value of the field before the upgrade (string, number, boolean, or `null`)." + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "AgentUpgradeResponse": { + "description": "Response returned by the agent upgrade endpoint, combining the updated agent, its source Solution and template, and the full upgrade diff.", + "example": { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "upgrade_result": { + "changes": [ + { + "action": "update", + "description": "An example description.", + "field_changes": [ + { + "field": "name", + "locally_edited": true + } + ], + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "string", + "name": "Example Name", + "parent_template_config": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "resource": {}, + "resource_type": "tool", + "source_template_config": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + } + ], + "dry_run": true, + "mode": "full", + "review_fingerprint": "string", + "status": "upgraded", + "summary": { + "adds": 1, + "noops": 1, + "removes": 1, + "updates": 1 + } + } + }, + "properties": { + "agent": { + "$ref": "#/components/schemas/Agent", + "description": "The agent after the upgrade has been applied. `null` for dry-run requests where no changes were persisted." + }, + "solution": { + "$ref": "#/components/schemas/SolutionSummary", + "description": "Summary of the parent Solution the agent was upgraded from." + }, + "template": { + "$ref": "#/components/schemas/UpgradeTemplateSummary", + "description": "Summary of the AgentTemplate config (`cfg_...`) that was selected for this upgrade." + }, + "upgrade_result": { + "$ref": "#/components/schemas/AgentUpgradeResult", + "description": "Full upgrade diff including status, mode, dry-run flag, summary counts, and per-resource change list." + } + }, + "required": [ + "solution", + "template", + "upgrade_result" + ], + "type": "object" + }, + "AgentUpgradeResult": { + "description": "The computed diff and outcome of an agent upgrade operation, including the full list of per-resource changes.", + "example": { + "changes": [ + { + "action": "update", + "description": "An example description.", + "field_changes": [ + { + "field": "name", + "locally_edited": true + } + ], + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "string", + "name": "Example Name", + "parent_template_config": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "resource": {}, + "resource_type": "tool", + "source_template_config": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + } + ], + "dry_run": true, + "mode": "full", + "review_fingerprint": "string", + "status": "upgraded", + "summary": { + "adds": 1, + "noops": 1, + "removes": 1, + "updates": 1 + } + }, + "properties": { + "changes": { + "description": "Ordered list of per-resource changes that will be (or were) applied by this upgrade.", + "items": { + "$ref": "#/components/schemas/AgentUpgradeChange" + }, + "type": "array" + }, + "dry_run": { + "description": "`true` when the request was a dry run and no changes were persisted to the agent.", + "example": true, + "type": "boolean" + }, + "mode": { + "description": "Upgrade mode that was used. One of `\"full\"` (apply all changes) or `\"review\"` (require fingerprint confirmation).", + "example": "full", + "type": "string" + }, + "review_fingerprint": { + "description": "Opaque fingerprint of the computed diff. Pass this value back as `review_fingerprint` to confirm and apply a `\"review\"` mode upgrade.", + "example": "string", + "type": "string" + }, + "status": { + "description": "Outcome of the upgrade. `\"ready\"` for a dry-run (no changes applied); `\"upgraded\"` when the upgrade was committed.", + "example": "upgraded", + "type": "string" + }, + "summary": { + "$ref": "#/components/schemas/AgentUpgradeSummary", + "description": "Aggregate counts of adds, updates, removes, and noops across all child resources." + } + }, + "required": [ + "status", + "mode", + "dry_run", + "summary", + "changes" + ], + "type": "object" + }, + "AgentUpgradeSummary": { + "description": "Aggregate counts of each change type produced by an agent upgrade diff.", + "example": { + "adds": 1, + "noops": 1, + "removes": 1, + "updates": 1 + }, + "properties": { + "adds": { + "description": "Number of child resources that will be created by this upgrade.", + "example": 1, + "type": "integer" + }, + "noops": { + "description": "Number of child resources with no changes in this upgrade.", + "example": 1, + "type": "integer" + }, + "removes": { + "description": "Number of child resources that will be removed by this upgrade.", + "example": 1, + "type": "integer" + }, + "updates": { + "description": "Number of child resources that will be updated by this upgrade.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "adds", + "updates", + "removes", + "noops" + ], + "type": "object" + }, + "Artifact": { + "description": "A versioned artifact produced or managed by an agent, such as a generated file, report, or code output.", + "example": { + "agent": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "current_version": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "file": "string", + "file_name": "Example Name", + "file_url": "https://example.com", + "id": "art_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + }, + "properties": { + "agent": { + "description": "ID of the agent that produced this artifact (`agt_...`). `null` if not agent-produced.", + "example": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "content_type": { + "description": "MIME type of the current version's file, e.g. `\"text/csv\"` or `\"image/png\"`. `null` if no file is attached.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When the artifact was first created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "current_version": { + "description": "ID of the current (latest published) artifact version (`artv_...`). `null` if no version has been published.", + "example": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "description": { + "description": "Optional longer description of the artifact's contents or purpose. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "file": { + "description": "Storage file ID for the current version (`fil_...`). `null` if no file is attached.", + "example": "string", + "type": "string" + }, + "file_name": { + "description": "Original filename of the current version's file, e.g. `\"output.csv\"`. `null` if no file is attached.", + "example": "Example Name", + "type": "string" + }, + "file_url": { + "description": "Short-lived signed URL for downloading the current version's file. `null` if no file is attached.", + "example": "https://example.com", + "type": "string" + }, + "id": { + "description": "Artifact ID (`art_...`).", + "example": "art_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "$ref": "#/components/schemas/ImageSource", + "description": "Image source metadata for rendering the current version's file inline. Present only when `content_type` starts with `\"image/\"`. `null` otherwise." + }, + "name": { + "description": "Human-readable name for the artifact, e.g. `\"Q2 Report\"`. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this artifact belongs to (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Identifier of the sandbox environment associated with this artifact. `null` if not sandbox-scoped.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this artifact (`tea_...`). `null` if not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread in which this artifact was created (`thr_...`). `null` if not thread-scoped.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the artifact record was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user who created this artifact (`usr_...`). `null` if not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "version": { + "description": "Current version number of the artifact. Increments each time a new version is published.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "Attachment": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "$ref": "#/components/schemas/ImageSource", + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise." + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "items": { + "$ref": "#/components/schemas/MediaVariant" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "AuthTokens": { + "description": "Credential bundle returned after a successful authentication exchange. Contains the access token, refresh token, and the authenticated user.", + "example": { + "expires_in": 3600, + "metadata": { + "key": "value" + }, + "refresh_token": "rt_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6", + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfMDEiLCJleHAiOjE3MTcwMDAwMDB9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + "token_type": "Bearer", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + }, + "properties": { + "expires_in": { + "description": "Number of seconds until `token` expires. After this period, use `refresh_token` to obtain a new access token.", + "example": 3600, + "type": "integer", + "x-sdk": "token_expiry" + }, + "metadata": { + "description": "Optional auxiliary data associated with this authentication event, such as `onboarding_job_id` when the user is completing onboarding. `null` when no extra context is present.", + "example": { + "key": "value" + }, + "type": "object" + }, + "refresh_token": { + "description": "Long-lived opaque refresh token. Use this to obtain a new access token when `token` expires.", + "example": "rt_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6", + "type": "string", + "x-sdk": "refresh_token" + }, + "token": { + "description": "Short-lived JWT access token. Include this value in the `Authorization: Bearer ` header for all authenticated API requests.", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfMDEiLCJleHAiOjE3MTcwMDAwMDB9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + "type": "string", + "x-sdk": "access_token" + }, + "token_type": { + "description": "Token scheme. Always `\"Bearer\"`.", + "example": "Bearer", + "type": "string" + }, + "user": { + "$ref": "#/components/schemas/User", + "description": "The user who authenticated. Contains the user's profile and account details." + } + }, + "required": [ + "token", + "refresh_token", + "user", + "token_type", + "expires_in" + ], + "type": "object" + }, + "AutomationParticipantSlot": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "AutomationPrefills": { + "description": "Locked payload and participant values supplied by the automation owner.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + }, + "AutomationRun": { + "description": "A single execution of an automation triggered by a platform event or direct invocation. Captures the run's status, input payload, and final result.", + "example": { + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "automation": "aut_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "event_id": "string", + "id": "atr_0aBcDeFgHiJkLmNoPqRsTu", + "participants": {}, + "payload": {}, + "result": {}, + "status": "pending", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "app": { + "description": "ID of the app that owns this automation run (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "automation": { + "description": "ID of the automation that was executed (`aut_...`).", + "example": "aut_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the automation run was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "event_id": { + "description": "ID of the platform event that triggered this run. `null` for directly invoked automations.", + "example": "string", + "type": "string" + }, + "id": { + "description": "Automation run ID (`atr_...`).", + "example": "atr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "participants": { + "description": "Invoke-time map of symbolic participant references to agent IDs. `null` when no participants were supplied.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "The input event payload that triggered this run. Structure varies by automation type. Defaults to an empty object if no payload was provided.", + "example": {}, + "type": "object" + }, + "result": { + "description": "The output produced after the automation finished executing. Contains workflow-defined keys alongside any returned output. `null` if the run has not yet completed.", + "example": {}, + "type": "object" + }, + "status": { + "description": "Current execution status of the run. One of `\"pending\"` (queued, not yet started), `\"running\"` (actively executing), `\"completed\"` (finished successfully), `\"failed\"` (finished with an error), or `\"cancelled\"` (stopped before completion).", + "example": "pending", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this run (`tea_...`). `null` if the run is owned by a user rather than a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the automation run record was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this run (`usr_...`). `null` if the run is owned by a team rather than a user.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "app", + "automation", + "status" + ], + "type": "object" + }, + "BugReport": { + "description": "A bug report or freeform feedback submission from any ArchAstro client. Bug reports are write-only for the submitting user and are not returned by any public list or show endpoint.", + "example": { + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "client": "agent_network_web", + "client_version": "1.4.2", + "context": { + "key": "value" + }, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "bgr_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "app": { + "description": "App ID (`dap_...`) of the developer app through which the report was submitted.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "client": { + "description": "The client application that submitted this report. One of `\"agent_network_web\"`, `\"cli\"`, or `\"developer_portal\"`.", + "example": "agent_network_web", + "type": "string" + }, + "client_version": { + "description": "Version string of the submitting client at the time of submission, e.g. `\"1.4.2\"`.", + "example": "1.4.2", + "type": "string" + }, + "context": { + "description": "Optional free-form JSON object providing additional context captured by the client (e.g. viewport size, active route). `null` when no context was provided. Maximum 5 KB when serialized.", + "example": { + "key": "value" + }, + "type": "object" + }, + "created_at": { + "description": "When the bug report was submitted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Freeform text describing the issue or feedback, as entered by the user. Up to 10,000 characters.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Bug report ID (`bgr_...`).", + "example": "bgr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) scoping this report. `null` when the user's account is not part of an organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Sandbox ID (`dsb_...`) active at submission time. `null` when the report was not submitted from a sandbox context.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "team": { + "description": "Team ID (`tem_...`) of the team the submitting user belonged to at submission time. `null` when the user had no active team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the bug report record was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "description", + "client", + "client_version" + ], + "type": "object" + }, + "BuiltinTool": { + "description": "A single callable tool within a builtin tool catalog entry. Represents one discrete function an agent can invoke.", + "example": { + "description": "An example description.", + "name": "Example Name" + }, + "properties": { + "description": { + "description": "Human-readable explanation of what the tool does. Surfaced to the agent as part of tool selection context. `null` when no description has been defined.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "Machine-readable name of the tool as it is registered with the agent runtime, e.g. `\"web_search\"` or `\"github_create_issue\"`.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "BuiltinToolCatalogEntry": { + "description": "A catalog entry describing a category of platform-provided (builtin) tools that can be enabled for an agent. Each entry groups one or more individual tools under a shared key, label, and configuration schema.", + "example": { + "config_schema": {}, + "description": "An example description.", + "instruction": "string", + "key": "web_search", + "label": "Web Search", + "multi_instance_mode": "namespaced", + "providers": [ + "string" + ], + "requires_integration": true, + "server_tool_type": "string", + "tools": [ + { + "description": "An example description.", + "name": "Example Name" + } + ] + }, + "properties": { + "config_schema": { + "description": "JSON Schema object describing the configuration options for this tool category. Clients should use this schema to render and validate configuration forms before submitting. `null` when no configuration is needed.", + "example": {}, + "type": "object" + }, + "description": { + "description": "Short prose description of what this tool category does. Suitable for display in setup UIs. `null` when no description has been defined.", + "example": "An example description.", + "type": "string" + }, + "instruction": { + "description": "Additional guidance surfaced to the agent at runtime when this tool category is enabled. `null` when no custom instruction is set.", + "example": "string", + "type": "string" + }, + "key": { + "description": "Unique slug identifying this tool category, e.g. `\"web_search\"` or `\"github\"`.", + "example": "web_search", + "type": "string" + }, + "label": { + "description": "Human-readable display name for the tool category, e.g. `\"Web Search\"`. `null` when no label has been assigned.", + "example": "Web Search", + "type": "string" + }, + "multi_instance_mode": { + "description": "Controls whether multiple instances of this tool category may be enabled simultaneously. `\"namespaced\"` — multiple instances allowed; each must carry a `name_prefix` to distinguish them. `\"passthrough\"` — multiple instances allowed without a `name_prefix`; names are derived from the underlying source. `null` — single-instance only.", + "example": "namespaced", + "type": "string" + }, + "providers": { + "description": "List of integration provider slugs that can back this tool category, e.g. `[\"github\", \"gitlab\"]`. Empty when the tool is provider-agnostic.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "requires_integration": { + "description": "Whether enabling this tool category requires the user to connect a third-party integration. `true` means at least one active integration of the appropriate type must exist before the tool can be used.", + "example": true, + "type": "boolean" + }, + "server_tool_type": { + "description": "Internal type identifier used by the platform server when registering these tools. `null` for client-side-only tool categories.", + "example": "string", + "type": "string" + }, + "tools": { + "description": "Array of individual tool definitions included in this category. Each entry describes a single callable tool with its own name and description.", + "items": { + "$ref": "#/components/schemas/BuiltinTool" + }, + "type": "array" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "ChannelAck": { + "description": "Empty acknowledgement payload returned by channel message handlers that produce no data. The wire envelope is `{\"status\": \"ok\", \"response\": {}}`.", + "properties": {}, + "type": "object" + }, + "ChatForkThreadResponse": { + "description": "Response returned after forking a chat thread. Contains the new thread, its initial chat-room snapshot, and the owning team when applicable.", + "example": { + "chat_model": { + "after_cursor": "string", + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "before_cursor": "string", + "is_transient": true, + "members": [ + { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "membership_type": "owner", + "type": "user", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + } + ], + "messages": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ], + "messages_loaded_on_last_update": 1, + "team": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "thread": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + } + }, + "team": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "thread": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + } + }, + "properties": { + "chat_model": { + "$ref": "#/components/schemas/ChatRoomModel", + "description": "Initial chat-room render snapshot for the forked thread, including members and loaded messages. `null` for transient threads whose room model is suppressed." + }, + "team": { + "$ref": "#/components/schemas/Team", + "description": "Team that owns the forked thread. Present only when the original thread was team-scoped; `null` for personal threads." + }, + "thread": { + "$ref": "#/components/schemas/Thread", + "description": "The newly-created thread produced by the fork operation." + } + }, + "required": [ + "thread" + ], + "type": "object" + }, + "ChatLoadMoreMessagesResponse": { + "description": "Response returned after loading an additional page of chat messages. Contains a refreshed chat-room snapshot with the newly-fetched messages merged in.", + "example": { + "data": { + "after_cursor": "string", + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "before_cursor": "string", + "is_transient": true, + "members": [ + { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "membership_type": "owner", + "type": "user", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + } + ], + "messages": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ], + "messages_loaded_on_last_update": 1, + "team": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "thread": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + } + } + }, + "properties": { + "data": { + "$ref": "#/components/schemas/ChatRoomModel", + "description": "Updated chat-room snapshot for the thread, incorporating the newly-loaded page of messages alongside any previously loaded messages." + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "ChatMarkThreadReadResponse": { + "description": "Response returned after marking a chat thread as read. Confirms that the read marker was successfully recorded for the authenticated user.", + "example": { + "success": true + }, + "properties": { + "success": { + "description": "Indicates whether the read marker was successfully applied. Always `true` on success; errors are returned as channel error replies rather than a `false` value here.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "success" + ], + "type": "object" + }, + "ChatMember": { + "description": "A participant in a chat thread, which may be either a human user or an AI agent. Exactly one of `user` or `agent` is populated depending on `type`.", + "example": { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "membership_type": "owner", + "type": "user", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + }, + "properties": { + "agent": { + "$ref": "#/components/schemas/Agent", + "description": "Full agent object for this member. Populated when `type` is `\"agent\"`; `null` for user members." + }, + "membership_type": { + "description": "Role of this member within the thread. Common values are `\"owner\"` and `\"member\"`. `null` when the membership type is not applicable.", + "example": "owner", + "type": "string" + }, + "type": { + "description": "Kind of participant. One of `\"user\"` (a human user) or `\"agent\"` (an AI agent).", + "example": "user", + "type": "string" + }, + "user": { + "$ref": "#/components/schemas/User", + "description": "Full user object for this member. Populated when `type` is `\"user\"`; `null` for agent members." + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "ChatMessageListResponse": { + "description": "Response returned when listing the messages of a joined chat thread. Contains the set of messages currently loaded for the thread.", + "example": { + "messages": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ] + }, + "properties": { + "messages": { + "description": "Ordered array of message objects currently loaded for the thread, from oldest to newest. Use the `load_more_messages` channel message to fetch earlier pages.", + "items": { + "$ref": "#/components/schemas/Message" + }, + "type": "array" + } + }, + "required": [ + "messages" + ], + "type": "object" + }, + "ChatPostMessageResponse": { + "description": "Response returned after successfully posting a message to a chat thread. Contains the persisted message object echoed back to the sender.", + "example": { + "message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + }, + "properties": { + "message": { + "$ref": "#/components/schemas/Message", + "description": "The message that was created and stored. Contains the full message object including its assigned ID, author, content, and timestamps." + } + }, + "required": [ + "message" + ], + "type": "object" + }, + "ChatRoomModel": { + "description": "A point-in-time snapshot of a chat room's state, including its loaded messages, member roster, and pagination cursors. Returned when loading or refreshing a thread's message list.", + "example": { + "after_cursor": "string", + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "before_cursor": "string", + "is_transient": true, + "members": [ + { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "membership_type": "owner", + "type": "user", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + } + ], + "messages": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ], + "messages_loaded_on_last_update": 1, + "team": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "thread": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + } + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor to pass when fetching messages newer than those in this snapshot. `null` when this snapshot already reflects the latest messages.", + "example": "string", + "type": "string" + }, + "agent": { + "$ref": "#/components/schemas/Agent", + "description": "The agent associated with this chat room. `null` when no agent is attached." + }, + "before_cursor": { + "description": "Opaque cursor to pass when fetching messages older than those in this snapshot. `null` when the beginning of the thread history has been reached.", + "example": "string", + "type": "string" + }, + "is_transient": { + "description": "Whether this thread is ephemeral. Transient threads are not retained in long-term storage and may be deleted when the session ends.", + "example": true, + "type": "boolean" + }, + "members": { + "description": "All active members of the chat room, including both human users and agents.", + "items": { + "$ref": "#/components/schemas/ChatMember" + }, + "type": "array" + }, + "messages": { + "description": "The page of messages currently loaded for the thread, ordered chronologically. Use `before_cursor` or `after_cursor` to page through additional history.", + "items": { + "$ref": "#/components/schemas/Message" + }, + "type": "array" + }, + "messages_loaded_on_last_update": { + "description": "Number of messages that were added to the snapshot in the most recent incremental update. `null` on the initial load.", + "example": 1, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/Team", + "description": "The team that owns this thread. `null` for threads scoped to an individual user rather than a team." + }, + "thread": { + "$ref": "#/components/schemas/Thread", + "description": "The parent thread whose message history and membership this snapshot represents." + } + }, + "required": [ + "messages", + "members", + "thread", + "is_transient" + ], + "type": "object" + }, + "ComputerExecResult": { + "description": "The result of executing a shell command on an agent's computer environment. Contains the captured output and the process exit code.", + "example": { + "exit_code": 0, + "output": "Hello, world!\n" + }, + "properties": { + "exit_code": { + "description": "The UNIX exit code returned by the process. `0` indicates success; any non-zero value indicates an error. `null` if the process did not terminate normally.", + "example": 0, + "type": "integer" + }, + "output": { + "description": "The combined stdout and stderr output produced by the command. `null` if the command produced no output.", + "example": "Hello, world!\n", + "type": "string" + } + }, + "type": "object" + }, + "Config": { + "description": "A versioned config file owned by a team or user, representing a typed artifact such as an agent definition or API tool specification.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "current_version": { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + }, + "id": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "is_archived": true, + "kind": "Agent", + "lookup_key": "string", + "mime_type": "application/json", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "parent_solution": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "raw_content": "string", + "relative_path": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "virtual_path": "agents/my-agent.yaml" + }, + "properties": { + "agent": { + "description": "Agent ID (`agt_...`) associated with this config. `null` if not linked to an agent.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When this config was first created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "current_version": { + "$ref": "#/components/schemas/ConfigVersion", + "description": "The most recently saved version of this config. `null` if the config has never been saved with content." + }, + "id": { + "description": "Config ID (`cfg_...`).", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_archived": { + "description": "Whether this config has been archived. Archived configs are hidden from default listings but remain accessible by ID.", + "example": true, + "type": "boolean" + }, + "kind": { + "description": "Type of config, e.g. `\"Agent\"` or `\"APITool\"`. Determines which fields and validation rules apply.", + "example": "Agent", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined key used to look up this config without knowing its ID. `null` if not set.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the config's content, e.g. `\"text/yaml\"`. `null` if not determined.", + "example": "application/json", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) this config belongs to. `null` for configs not scoped to an org.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "Parent bundle config ID (`cfg_...`). Present only for configs that are children of a bundle; `null` otherwise.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent_solution": { + "description": "ID (`cfg_...`) of the solution config this config was imported with. `null` if the config was not imported via a solution.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "raw_content": { + "description": "Raw file content as a string. Populated only for system configs; `null` for user-owned configs.", + "example": "string", + "type": "string" + }, + "relative_path": { + "description": "Path of this config relative to its parent bundle root. Present only for bundle children; `null` otherwise.", + "example": "string", + "type": "string" + }, + "sandbox": { + "description": "Sandbox identifier this config belongs to. `null` for production configs.", + "example": "string", + "type": "string" + }, + "team": { + "description": "Team ID (`tea_...`) that owns this config. `null` for personal (user-scoped) configs.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When this config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) who owns this config. `null` for team-scoped configs.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "virtual_path": { + "description": "Logical path uniquely identifying this config within its team, e.g. `\"agents/my-agent.yaml\"`. `null` for configs without an explicit path.", + "example": "agents/my-agent.yaml", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + }, + "ConfigFacets": { + "description": "Aggregated facet counts for the authenticated viewer's configs. Reports all distinct kinds and path prefixes across the full dataset, regardless of any active list filters.", + "example": { + "kinds": [ + { + "count": 1, + "kind": "Agent" + } + ], + "path_prefixes": [ + { + "count": 1, + "prefix": "agents/" + } + ] + }, + "properties": { + "kinds": { + "description": "All distinct config kinds present in the viewer's dataset, each with its total count. Use these values to populate kind filter options.", + "items": { + "$ref": "#/components/schemas/ConfigKindFacet" + }, + "type": "array" + }, + "path_prefixes": { + "description": "All distinct slash-terminated path prefixes present in the viewer's dataset, each with its total count. Use these values to populate path prefix filter options.", + "items": { + "$ref": "#/components/schemas/ConfigPathPrefixFacet" + }, + "type": "array" + } + }, + "required": [ + "kinds", + "path_prefixes" + ], + "type": "object" + }, + "ConfigKindFacet": { + "description": "A facet entry grouping configs by kind, returning the kind name and the number of matching configs visible to the authenticated viewer.", + "example": { + "count": 1, + "kind": "Agent" + }, + "properties": { + "count": { + "description": "Number of configs of this kind that are visible to the authenticated viewer. Always `0` or greater.", + "example": 1, + "type": "integer" + }, + "kind": { + "description": "The config kind identifier (e.g., `\"Agent\"`, `\"WorkflowGraph\"`). Matches the `kind` field on config objects.", + "example": "Agent", + "type": "string" + } + }, + "required": [ + "kind", + "count" + ], + "type": "object" + }, + "ConfigKindSchema": { + "description": "The JSON Schema definition and sample YAML for a specific config kind, used to validate and scaffold new configs of that kind.", + "example": { + "json_schema": {}, + "kind": "Agent", + "sample_yaml": "string" + }, + "properties": { + "json_schema": { + "description": "JSON Schema object describing the valid structure of a config of this kind. `null` when no schema has been registered for this kind.", + "example": {}, + "type": "object" + }, + "kind": { + "description": "The config kind identifier (e.g., `\"Agent\"`, `\"WorkflowGraph\"`). Matches the `kind` field on config objects.", + "example": "Agent", + "type": "string" + }, + "sample_yaml": { + "description": "A sample YAML document illustrating a minimal valid config of this kind. `null` when no sample has been registered for this kind.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "ConfigPathPrefixFacet": { + "description": "A facet entry grouping configs by their leading path segment, returning the prefix and the number of matching configs visible to the authenticated viewer.", + "example": { + "count": 1, + "prefix": "agents/" + }, + "properties": { + "count": { + "description": "Number of configs whose `virtual_path` begins with this prefix that are visible to the authenticated viewer. Always `0` or greater.", + "example": 1, + "type": "integer" + }, + "prefix": { + "description": "The leading path segment of the config's `virtual_path`, always slash-terminated (e.g., `\"agents/\"`, `\"__editor/\"`). Pass this value as the `path_prefix` filter to narrow config listings.", + "example": "agents/", + "type": "string" + } + }, + "required": [ + "prefix", + "count" + ], + "type": "object" + }, + "ConfigVersion": { + "description": "A single immutable snapshot of a config's content, created each time the config is saved.", + "example": { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + }, + "properties": { + "change_description": { + "description": "Human-readable summary of what changed in this version, as provided by the author. `null` if no description was supplied.", + "example": "An example description.", + "type": "string" + }, + "content_hash": { + "description": "SHA-256 digest of the raw config content encoded as `sha256:`. Uses the same algorithm as the CLI `computeContentHash` helper. `null` for versions created before this field was introduced.", + "example": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "type": "string" + }, + "created_at": { + "description": "When this config version was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "data": { + "description": "Arbitrary structured metadata stored alongside this version. `null` when no extra data was provided.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Config version ID (`cfv_...`).", + "example": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this config version. `null` for personal configs.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Sandbox ID (`sbx_...`) this version was saved under. `null` for production configs.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution_config_version": { + "description": "Config version ID (`cfv_...`) for the Solution version this config version was installed from. `null` for standalone configs and legacy rows.", + "example": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "version_number": { + "description": "Monotonically increasing integer identifying this version within the config. Starts at 1.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "version_number" + ], + "type": "object" + }, + "ContextDocument": { + "description": "A context document stored within a context source. Carries metadata and size information only; retrieve the full text content via the `/content` endpoint.\n", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "content_hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "id": "cdo_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "source": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "total_lines": 1, + "total_size": 2048, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this document (`agi_...`). `null` if owned by a user or team.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "content_hash": { + "description": "Lowercase-hex sha256 of the document's full text, covering content only — not `title` or `metadata`. Compare it against a hash of your local copy to decide whether the document needs re-ingesting, without fetching `/content`. `null` for documents ingested before this field existed; it is not backfilled.", + "example": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", + "type": "string" + }, + "created_at": { + "description": "When the document was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the backing storage file (`fil_...`) when the document is file-backed. `null` for inline documents.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "id": { + "description": "Context document ID (`cdo_...`).", + "example": "cdo_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the document. Shape varies by source type.", + "example": { + "key": "value" + }, + "type": "object" + }, + "source": { + "description": "ID of the context source this document belongs to (`cso_...`).", + "example": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this document (`tem_...`). `null` if owned by a user or agent.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "title": { + "description": "Human-readable display title of the document. `null` if no title has been set.", + "example": "Example Title", + "type": "string" + }, + "total_lines": { + "description": "Total number of lines in the document's text content. `0` if the document has no content.", + "example": 1, + "type": "integer" + }, + "total_size": { + "description": "Total byte size of the document's text content. `0` if the document has no content.", + "example": 2048, + "type": "integer" + }, + "updated_at": { + "description": "When the document was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this document (`usr_...`). `null` if owned by a team or agent.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "ContextDocumentContent": { + "description": "The text content of a context document, optionally sliced by line or byte range. Includes totals and slice boundary fields for the requested unit.", + "example": { + "content": "This is the document content.", + "end_byte": 1, + "end_line": 1, + "id": "cdo_0aBcDeFgHiJkLmNoPqRsTu", + "limit": 100, + "metadata": { + "key": "value" + }, + "offset": 1, + "start_byte": 1, + "start_line": 1, + "title": "Example Title", + "total_lines": 1, + "total_size": 2048, + "unit": "lines" + }, + "properties": { + "content": { + "description": "Text of the document. Contains the full content when no `offset`/`limit` was requested, or only the requested slice otherwise.", + "example": "This is the document content.", + "type": "string" + }, + "end_byte": { + "description": "Zero-based exclusive index of the last byte in `content` (i.e. the slice covers bytes `start_byte..end_byte-1`). Populated only when `unit` is `\"bytes\"`; `null` otherwise.", + "example": 1, + "type": "integer" + }, + "end_line": { + "description": "1-indexed line number of the last line included in `content` (i.e. the slice covers lines `start_line` through `end_line` inclusive). Populated only when `unit` is `\"lines\"`; `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Context document ID (`cdo_...`).", + "example": "cdo_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "limit": { + "description": "The `limit` value echoed from the request. `null` when no limit was requested.", + "example": 100, + "type": "integer" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the document, such as source URL or author. `null` if no metadata was recorded.", + "example": { + "key": "value" + }, + "type": "object" + }, + "offset": { + "description": "The `offset` value echoed from the request. `null` when no offset was requested.", + "example": 1, + "type": "integer" + }, + "start_byte": { + "description": "Zero-based index of the first byte included in `content`. Populated only when `unit` is `\"bytes\"`; `null` otherwise.", + "example": 1, + "type": "integer" + }, + "start_line": { + "description": "1-indexed line number of the first line included in `content`. Populated only when `unit` is `\"lines\"`; `null` otherwise.", + "example": 1, + "type": "integer" + }, + "title": { + "description": "Human-readable display title of the document. `null` if the document has no title set.", + "example": "Example Title", + "type": "string" + }, + "total_lines": { + "description": "Total number of lines in the document's full content, regardless of any slice.", + "example": 1, + "type": "integer" + }, + "total_size": { + "description": "Total byte size of the document's full content, regardless of any slice.", + "example": 2048, + "type": "integer" + }, + "unit": { + "description": "Slice unit used when `offset` and `limit` were provided. One of `\"lines\"` (default) or `\"bytes\"`. `null` when no slice was requested.", + "example": "lines", + "type": "string" + } + }, + "required": [ + "id", + "content", + "total_size", + "total_lines" + ], + "type": "object" + }, + "ContextIngestion": { + "description": "A context ingestion job that processes a context source and populates its documents. Tracks status and timing from submission through completion or failure.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "completed_at": "2024-01-01T00:00:00Z", + "created_at": "2024-01-01T00:00:00Z", + "error": {}, + "id": "cig_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "source": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "started_at": "2024-01-01T00:00:00Z", + "status": "pending", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that initiated this ingestion (`agi_...`). `null` if initiated by a user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "completed_at": { + "description": "When the ingestion job finished, either successfully or with a failure. `null` if still in progress.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_at": { + "description": "When the ingestion was submitted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "error": { + "description": "Structured error details when the ingestion has `status: \"failed\"`. `null` for any other status.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Context ingestion ID (`cig_...`).", + "example": "cig_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata associated with this ingestion run. Shape is caller-defined.", + "example": { + "key": "value" + }, + "type": "object" + }, + "source": { + "description": "ID of the context source being ingested (`cso_...`). `null` if the source has been deleted.", + "example": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "started_at": { + "description": "When the ingestion job began processing. `null` if the job is still pending.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "status": { + "description": "Current processing status. One of `\"pending\"`, `\"running\"`, `\"awaiting_callback\"`, `\"succeeded\"`, or `\"failed\"`.", + "example": "pending", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this ingestion (`tem_...`). `null` if owned by a user or agent.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the ingestion record was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that initiated this ingestion (`usr_...`). `null` if initiated by an agent.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "status" + ], + "type": "object" + }, + "CreatedPrivateServiceEnrollment": { + "description": "Creation-only private service enrollment response. The raw token is shown\nonce and is omitted from every read schema.\n", + "example": { + "enrollment_token": "string", + "enrollment_token_expires_at": "2024-01-01T00:00:00Z", + "generation": 1, + "id": "string", + "private_service": "string" + }, + "properties": { + "enrollment_token": { + "description": "One-time connector enrollment token. Store it immediately.", + "example": "string", + "type": "string" + }, + "enrollment_token_expires_at": { + "description": "When the one-time enrollment token expires.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "generation": { + "example": 1, + "type": "integer" + }, + "id": { + "example": "string", + "type": "string" + }, + "private_service": { + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "private_service", + "generation", + "enrollment_token", + "enrollment_token_expires_at" + ], + "type": "object" + }, + "CustomObject": { + "description": "A custom object belonging to an organization. Custom objects store arbitrary structured data defined by a schema type and are scoped to an org, team, or user.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "created_at": "2024-01-01T00:00:00Z", + "fields": { + "key": "value" + }, + "id": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "row_key": "string", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "schema_type": "contact", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + }, + "properties": { + "acl": { + "$ref": "#/components/schemas/Acl", + "description": "Access control list governing read and write access to this custom object. Only returned to resource owners and privileged or organization-admin viewers; `null` for everyone else." + }, + "created_at": { + "description": "When the custom object was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "fields": { + "description": "Map of field names to their current values as defined by the object's schema type.", + "example": { + "key": "value" + }, + "type": "object" + }, + "id": { + "description": "Unique identifier for the custom object (`cobj_...`).", + "example": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org": { + "description": "ID of the organization this object belongs to (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "row_key": { + "description": "An optional stable key used to identify this object by a caller-controlled string rather than its generated ID. `null` if not set.", + "example": "string", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this object is scoped to (`dsb_...`). `null` for production objects.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "schema_type": { + "description": "The lookup key of the schema type that defines this object's field structure. `null` if the schema type has not been set.", + "example": "contact", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this object (`tem_...`). `null` if the object is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the custom object was last modified (ISO 8601). `null` if the object has never been updated after creation.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this object (`usr_...`). `null` if the object is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "version": { + "description": "Optimistic concurrency version of the object. Increments with each successful update; pass this value in write operations to detect conflicting changes.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "CustomObjectJoinResponse": { + "description": "Initial authoritative snapshot returned by a custom-object channel join.", + "example": { + "connection_id": "string", + "fields": {}, + "id": "string", + "presence": [ + {} + ], + "readonly": true + }, + "properties": { + "connection_id": { + "description": "Collision-free identifier for this browser connection.", + "example": "string", + "type": "string" + }, + "fields": { + "description": "Current materialized fields, or `null` while waiting for object creation.", + "example": {}, + "nullable": true, + "type": "object" + }, + "id": { + "description": "Custom-object ID, or `null` while a row-key subscription waits for creation.", + "example": "string", + "nullable": true, + "type": "string" + }, + "presence": { + "description": "Current ephemeral collaborator presence.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "readonly": { + "description": "Whether the current connection may only read the object.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "id", + "fields", + "readonly", + "connection_id", + "presence" + ], + "type": "object" + }, + "CustomObjectListResponse": { + "description": "A paginated page of custom objects returned by a list operation. Use the pagination fields to navigate through result sets.", + "example": { + "data": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "created_at": "2024-01-01T00:00:00Z", + "fields": { + "key": "value" + }, + "id": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "row_key": "string", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "schema_type": "contact", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 20, + "total_entries": 1, + "total_pages": 1 + }, + "properties": { + "data": { + "description": "Array of custom objects for the current page.", + "items": { + "$ref": "#/components/schemas/CustomObject" + }, + "type": "array" + }, + "has_next": { + "description": "`true` if a subsequent page of results exists; `false` if this is the last page.", + "example": true, + "type": "boolean" + }, + "has_prev": { + "description": "`true` if a preceding page of results exists; `false` if this is the first page.", + "example": true, + "type": "boolean" + }, + "page": { + "description": "The current page number (1-indexed).", + "example": 1, + "type": "integer" + }, + "page_size": { + "description": "Maximum number of results returned per page.", + "example": 20, + "type": "integer" + }, + "total_entries": { + "description": "Total number of custom objects matching the query across all pages.", + "example": 1, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages available for the current query.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "data", + "page", + "page_size", + "total_entries", + "total_pages", + "has_next", + "has_prev" + ], + "type": "object" + }, + "CustomObjectPresenceAck": { + "description": "Acknowledges an ephemeral custom-object presence update.", + "example": { + "connection_id": "string" + }, + "properties": { + "connection_id": { + "description": "Collision-free connection identifier assigned to this browser connection.", + "example": "string", + "type": "string" + } + }, + "required": [ + "connection_id" + ], + "type": "object" + }, + "CustomObjectSaveResponse": { + "description": "Acknowledges that the current custom-object document reached durable storage.", + "example": { + "version": 1 + }, + "properties": { + "version": { + "description": "Durable optimistic-concurrency version after the save.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "version" + ], + "type": "object" + }, + "CustomObjectUpdateFieldsResponse": { + "description": "Response returned after updating one or more fields on a custom object. Confirms the object that was modified and the field values that were applied.", + "example": { + "fields": { + "key": "value" + }, + "id": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "operation_id": "string" + }, + "properties": { + "fields": { + "description": "The materialized object fields after the update.", + "example": { + "key": "value" + }, + "type": "object" + }, + "id": { + "description": "ID of the custom object that was updated (`cobj_...`).", + "example": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "operation_id": { + "description": "Idempotency key acknowledged for this update.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "fields", + "operation_id" + ], + "type": "object" + }, + "Deployment": { + "description": "Deployment metadata.", + "example": { + "environment": "string", + "release": "string" + }, + "properties": { + "environment": { + "description": "Deployment environment, or `null` when it is not configured.", + "example": "string", + "nullable": true, + "type": "string" + }, + "release": { + "description": "Opaque SHA-256 fingerprint of the image reference, or `null` in local development.", + "example": "string", + "nullable": true, + "type": "string" + } + }, + "type": "object" + }, + "DeviceAuthorizationDetailsResponse": { + "description": "User-visible details for a pending OAuth 2.0 device authorization.", + "example": { + "client_name": "Example Name", + "expires_at": "2024-01-01T00:00:00Z", + "scopes": [ + "string" + ] + }, + "properties": { + "client_name": { + "description": "Name of the client requesting authorization.", + "example": "Example Name", + "type": "string" + }, + "expires_at": { + "description": "Expiration time for the pending device authorization.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "scopes": { + "description": "Scopes the client is requesting.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "client_name", + "scopes", + "expires_at" + ], + "type": "object" + }, + "DeviceAuthorizationResponse": { + "description": "The initial response from an OAuth 2.0 Device Authorization Grant request, containing the codes and URIs needed to complete device authentication.", + "example": { + "device_code": "string", + "expires_in": 1800, + "interval": 5, + "user_code": "WDJB-MJHT", + "verification_uri": "https://example.com", + "verification_uri_complete": "string" + }, + "properties": { + "device_code": { + "description": "Opaque code identifying this device authorization session. Pass this value when polling the token endpoint; do not display it to the user.", + "example": "string", + "type": "string" + }, + "expires_in": { + "description": "Number of seconds until the `device_code` and `user_code` expire. After expiry the user must restart the authorization flow.", + "example": 1800, + "type": "integer" + }, + "interval": { + "description": "Minimum number of seconds to wait between polling attempts on the token endpoint. Polling more frequently will result in a `slow_down` error.", + "example": 5, + "type": "integer" + }, + "user_code": { + "description": "Short alphanumeric code the user must enter at `verification_uri` to authorize the device.", + "example": "WDJB-MJHT", + "type": "string" + }, + "verification_uri": { + "description": "URL the user visits to enter the `user_code` and approve the authorization request.", + "example": "https://example.com", + "type": "string" + }, + "verification_uri_complete": { + "description": "Full verification URL with the `user_code` pre-filled as a query parameter. Display this as a QR code or deep link to reduce manual entry.", + "example": "string", + "type": "string" + } + }, + "required": [ + "device_code", + "user_code", + "verification_uri", + "verification_uri_complete", + "expires_in", + "interval" + ], + "type": "object" + }, + "DeviceAuthorizationStatusResponse": { + "description": "The result of a completed OAuth 2.0 Device Authorization flow, indicating whether the user approved or denied the device's access request.", + "example": { + "status": "approved" + }, + "properties": { + "status": { + "description": "Outcome of the device authorization request. One of `\"approved\"` (the user granted access) or `\"denied\"` (the user rejected or cancelled the request).", + "example": "approved", + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Extraction": { + "description": "An extraction job: yields text from a document or website into a destination namespace, without committing knowledge to an agent.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "byte_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "destination": {}, + "failure_reason": "fetch_failed", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "id": "ext_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "document", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "output_count": 1, + "outputs": [ + { + "created_at": "2024-01-01T00:00:00Z", + "file": { + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "filename": "document.pdf", + "id": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "share_url": "https://example.com", + "size": 1024, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "id": "exo_0aBcDeFgHiJkLmNoPqRsTu", + "ordinal": 1, + "source_url": "https://example.com", + "state": "done" + } + ], + "state": "pending", + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com" + }, + "properties": { + "agent": { + "description": "Owning agent (`agt_...`); `null` when not agent-scoped.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "byte_count": { + "description": "Total bytes across produced storage files (a derived aggregate).", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the extraction was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "destination": { + "description": "Where outputs were written: `{ kind, path_prefix }`.", + "example": {}, + "type": "object" + }, + "failure_reason": { + "description": "Failure category when `state` is `failed`; `null` otherwise.", + "enum": [ + "fetch_failed", + "unsupported_content", + "extraction_failed", + "timeout", + "internal_error" + ], + "example": "fetch_failed", + "type": "string" + }, + "file": { + "description": "Source file (`fil_...`) for document extraction; `null` for link/site.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "id": { + "description": "Extraction ID (`ext_...`).", + "example": "ext_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "What is being extracted.", + "enum": [ + "document", + "link", + "site" + ], + "example": "document", + "type": "string" + }, + "org": { + "description": "Owning organization (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "output_count": { + "description": "Number of produced output files (a derived aggregate).", + "example": 1, + "type": "integer" + }, + "outputs": { + "description": "Produced output files; populated only when the association is preloaded.", + "items": { + "$ref": "#/components/schemas/ExtractionOutput" + }, + "type": "array" + }, + "state": { + "description": "Lifecycle state of the extraction job.", + "enum": [ + "pending", + "running", + "done", + "failed" + ], + "example": "pending", + "type": "string" + }, + "updated_at": { + "description": "When the extraction was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Source URL for link/site extraction; `null` for document.", + "example": "https://example.com", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "ExtractionOutput": { + "description": "A produced file tracked by an extraction. Type, size, and URL live on the file it points at.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "file": { + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "filename": "document.pdf", + "id": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "share_url": "https://example.com", + "size": 1024, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "id": "exo_0aBcDeFgHiJkLmNoPqRsTu", + "ordinal": 1, + "source_url": "https://example.com", + "state": "done" + }, + "properties": { + "created_at": { + "description": "When this output was produced (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "$ref": "#/components/schemas/StorageFile", + "description": "The produced file. For a config destination this is the `Storage.File` backing the versioned config row; type, size, and URL live here." + }, + "id": { + "description": "Output ID (`exo_...`).", + "example": "exo_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "ordinal": { + "description": "Position of this output within the extraction's output set.", + "example": 1, + "type": "integer" + }, + "source_url": { + "description": "The crawled page path or document path this output came from.", + "example": "https://example.com", + "type": "string" + }, + "state": { + "description": "Output state.", + "enum": [ + "done", + "failed" + ], + "example": "done", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "HealthActionListResponse": { + "description": "List response containing agent health actions for a given agent or organization.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "depends_on": [ + "string" + ], + "description": "An example description.", + "id": "aha_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "env_var", + "last_verified_at": "2024-01-01T00:00:00Z", + "last_verifier_message": "string", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "source": "setup", + "status": "pending", + "title": "Example Title", + "updated_at": "2024-01-01T00:00:00Z", + "verify_config": {} + } + ] + }, + "properties": { + "data": { + "description": "Array of agent health action objects representing setup checklist items and probe-detected issues.", + "items": { + "$ref": "#/components/schemas/AgentHealthAction" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "ImageSource": { + "description": "Resolved metadata for an image, including its delivery URL, dimensions, and optional references to the underlying storage file or media record.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "Installation": { + "description": "An installation representing a connection between an agent and an external service or enablement channel. Tracks configuration, lifecycle state, and any bound integration.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "config": {}, + "created_at": "2024-01-01T00:00:00Z", + "id": "cin_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "enablement/github_app", + "lookup_key": "string", + "shared_integration": "int_0aBcDeFgHiJkLmNoPqRsTu", + "state": "active", + "status_payload": {}, + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this installation (`agi_...`). `null` if the installation has no agent owner.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "config": { + "description": "Kind-specific configuration object for this installation. Shape depends on the `kind` value. `null` if the kind requires no configuration.", + "example": {}, + "type": "object" + }, + "created_at": { + "description": "When the installation was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Installation ID (`cin_...`).", + "example": "cin_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Slug identifying the type of external service this installation connects to, e.g. `\"enablement/github_app\"` or `\"integration/gmail\"`. `null` if not set.", + "example": "enablement/github_app", + "type": "string" + }, + "lookup_key": { + "description": "Caller-assigned stable identifier for this installation, used to reference it in knowledge search `source_refs`. `null` if no lookup key was provided at creation time.", + "example": "string", + "type": "string" + }, + "shared_integration": { + "description": "ID of the shared org- or app-level integration bound to this installation (`int_...`). `null` if no integration has been bound.", + "example": "int_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "state": { + "description": "Current lifecycle state of the installation. One of `\"pending\"`, `\"active\"`, `\"paused\"`, or `\"error\"`. `\"error\"` indicates the installation was suspended due to a policy or compliance issue and requires attention.", + "example": "active", + "type": "string" + }, + "status_payload": { + "description": "Provider-supplied status detail for this installation, set during activation or event processing. `null` if no status has been reported.", + "example": {}, + "type": "object" + }, + "updated_at": { + "description": "When the installation record was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "InstallationKind": { + "description": "A supported installation kind describing a category of external service or enablement channel an agent can be connected to.", + "example": { + "accepts_sources": true, + "category": "integration", + "config_schema": {}, + "description": "An example description.", + "kind": "enablement/github_app", + "label": "GitHub App", + "provider": "github", + "requires_integration": true + }, + "properties": { + "accepts_sources": { + "description": "When `true`, sources can be attached to installations of this kind to supply additional context to the agent.", + "example": true, + "type": "boolean" + }, + "category": { + "description": "Grouping category for UI display purposes, e.g. `\"enablement\"` or `\"integration\"`. `null` if uncategorized.", + "example": "integration", + "type": "string" + }, + "config_schema": { + "description": "JSON Schema object describing the shape of the `config` parameter accepted when creating or updating an installation of this kind. `null` if the kind accepts no configuration.", + "example": {}, + "type": "object" + }, + "description": { + "description": "Short prose description of what this kind connects to and how it is used. `null` if no description is defined.", + "example": "An example description.", + "type": "string" + }, + "kind": { + "description": "Unique slug identifying this installation kind, e.g. `\"enablement/github_app\"`, `\"integration/gmail\"`, or `\"web/site\"`. Pass this value as `kind` when creating an installation.", + "example": "enablement/github_app", + "type": "string" + }, + "label": { + "description": "Human-readable display name for this kind, e.g. `\"GitHub App\"`. `null` if the kind has no label defined.", + "example": "GitHub App", + "type": "string" + }, + "provider": { + "description": "Identifier of the external provider this kind connects to, e.g. `\"github\"` or `\"slack\"`. `null` for kinds with no specific provider.", + "example": "github", + "type": "string" + }, + "requires_integration": { + "description": "When `true`, this kind requires an integration to be provided (either inline or via `shared_integration`) before the installation can be activated.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "InstallationKindListResponse": { + "description": "List response containing the publicly available installation kinds that can be used when configuring an agent installation.", + "example": { + "data": [ + { + "accepts_sources": true, + "category": "integration", + "config_schema": {}, + "description": "An example description.", + "kind": "enablement/github_app", + "label": "GitHub App", + "provider": "github", + "requires_integration": true + } + ] + }, + "properties": { + "data": { + "description": "Array of installation kind objects describing the available integration types and their configuration requirements.", + "items": { + "$ref": "#/components/schemas/InstallationKind" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "InstallationListResponse": { + "description": "Paginated list response containing installation objects for an agent.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "config": {}, + "created_at": "2024-01-01T00:00:00Z", + "id": "cin_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "enablement/github_app", + "lookup_key": "string", + "shared_integration": "int_0aBcDeFgHiJkLmNoPqRsTu", + "state": "active", + "status_payload": {}, + "updated_at": "2024-01-01T00:00:00Z" + } + ] + }, + "properties": { + "data": { + "description": "Array of installation objects returned for the current page.", + "items": { + "$ref": "#/components/schemas/Installation" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "InstallationSource": { + "description": "A source attached to an installation that supplies content for the agent's context. Sources are processed asynchronously after creation.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "context_installation": "cin_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "id": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "parent_source": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "payload": {}, + "state": "active", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "file/document", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this source (`agi_...`). `null` if the source is not agent-owned.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "context_installation": { + "description": "ID of the installation this source belongs to (`cin_...`). `null` if the source is not attached to an installation.", + "example": "cin_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the source was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Source ID (`cso_...`).", + "example": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata associated with this source. Shape is caller-defined. `null` if no metadata was set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "parent_source": { + "description": "ID of the parent source (`cso_...`) when this source was derived from another source. `null` for top-level sources.", + "example": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "payload": { + "description": "Type-specific payload provided when the source was created. The shape depends on the `type` value. `null` if no payload was supplied.", + "example": {}, + "type": "object" + }, + "state": { + "description": "Current lifecycle state of this source. One of `\"active\"` (ingestion running normally) or `\"paused\"` (ingestion suspended). Note that per-run ingestion progress is tracked separately and is not exposed on this field.", + "example": "active", + "type": "string" + }, + "team": { + "description": "ID of the team associated with this source (`tem_...`). `null` if the source has no team association.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the conversation thread linked to this source (`thr_...`). `null` if the source is not thread-scoped.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "type": { + "description": "Slug identifying the kind of content this source provides, e.g. `\"file/document\"` or `\"web/link\"`. `null` if the type is not set.", + "example": "file/document", + "type": "string" + }, + "updated_at": { + "description": "When the source record was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user associated with this source (`usr_...`). `null` if the source has no user association.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "InstallationSourceListResponse": { + "description": "Paginated list response containing installation source objects attached to an installation.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "context_installation": "cin_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "id": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "parent_source": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "payload": {}, + "state": "active", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "file/document", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ] + }, + "properties": { + "data": { + "description": "Array of installation source objects returned for the current page.", + "items": { + "$ref": "#/components/schemas/InstallationSource" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "InstalledConfigEntry": { + "description": "A slim summary of a single config record created during an agent install transaction. Returned as an entry in `AgentCreateResponse.installed_configs`.", + "example": { + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "my-skill", + "kind": "Skill", + "lookup_key": "my-skill" + }, + "properties": { + "id": { + "description": "ID of the persisted config record (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "key": { + "description": "Caller-supplied correlation key echoed back from the request. For top-level configs this is the original `lookup_key` (before any suffix is applied). For skill file children it is the composite `\":\"` string, since file rows have no lookup_key of their own.", + "example": "my-skill", + "type": "string" + }, + "kind": { + "description": "Type of config that was created. One of `\"Skill\"`, `\"File\"`, `\"Script\"`, `\"AgentTemplate\"`, or `\"Config\"`.", + "example": "Skill", + "type": "string" + }, + "lookup_key": { + "description": "Stored `lookup_key` for this config after any suffix has been applied. `null` for `File` children inside a skill bundle, which are keyed by `(parent_id, relative_path)` rather than by `lookup_key`.", + "example": "my-skill", + "type": "string" + } + }, + "required": [ + "key", + "id", + "kind" + ], + "type": "object" + }, + "InviteCreator": { + "description": "A minimal, public-safe projection of the user who sent an invite, exposed to unauthenticated recipients so they can render a join screen.\nOnly identity fields are included; sensitive fields such as email address and organization membership are omitted.\n", + "example": { + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "id": { + "description": "User ID of the inviter (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "name": { + "description": "Display name of the inviter. `null` when the inviter has not set a name on their account.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "$ref": "#/components/schemas/ImageSource", + "description": "Profile picture of the inviter. `null` when the inviter has no profile picture set." + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "KeyValueStorageEntry": { + "description": "A single key-value storage entry belonging to a user. Represents one key/value pair written to a user's isolated storage namespace within an app.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "key": "theme", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "value": "dark" + }, + "properties": { + "created_at": { + "description": "When this storage entry was first created (ISO 8601). `null` if not yet persisted.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "key": { + "description": "The string key used to store and look up this entry.", + "example": "theme", + "type": "string" + }, + "updated_at": { + "description": "When this storage entry was last updated (ISO 8601). `null` if not yet persisted.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user who owns this storage entry (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "value": { + "description": "The string value stored under `key` for this user.", + "example": "dark", + "type": "string" + } + }, + "required": [ + "user", + "key", + "value" + ], + "type": "object" + }, + "KeyValueStorageEntryPage": { + "description": "Paginated response envelope for the dual-mode key-value storage list endpoint. End-user (user-JWT) callers receive only `data`; developer and server-to-server callers also receive pagination metadata fields.", + "example": { + "data": [ + { + "created_at": "2024-01-01T00:00:00Z", + "key": "theme", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "user_email": "user@example.com", + "user_name": "Example Name", + "value": "dark" + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 20, + "total_entries": 1, + "total_pages": 1 + }, + "properties": { + "data": { + "description": "Array of key-value storage entries for the current page.", + "items": { + "$ref": "#/components/schemas/KeyValueStorageEntryWithUser" + }, + "type": "array" + }, + "has_next": { + "description": "Whether a subsequent page exists. `false` when the current page is the last page. Present only for developer and server-to-server callers.", + "example": true, + "type": "boolean" + }, + "has_prev": { + "description": "Whether a preceding page exists. `false` when the current page is the first page. Present only for developer and server-to-server callers.", + "example": true, + "type": "boolean" + }, + "page": { + "description": "Current page number (1-indexed). Present only for developer and server-to-server callers.", + "example": 1, + "type": "integer" + }, + "page_size": { + "description": "Maximum number of results returned per page. Present only for developer and server-to-server callers.", + "example": 20, + "type": "integer" + }, + "total_entries": { + "description": "Total number of storage entries matching the applied filters across all pages. Present only for developer and server-to-server callers.", + "example": 1, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages available given the current `page_size`. Present only for developer and server-to-server callers.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "KeyValueStorageEntryWithUser": { + "description": "A key-value storage entry enriched with owner information. Developer and server-to-server callers receive `user_email` and `user_name` populated; end-user (user-JWT) callers receive those fields as `null`.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "key": "theme", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "user_email": "user@example.com", + "user_name": "Example Name", + "value": "dark" + }, + "properties": { + "created_at": { + "description": "When this storage entry was first created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "key": { + "description": "The string key used to store and look up this entry.", + "example": "theme", + "type": "string" + }, + "updated_at": { + "description": "When this storage entry was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user who owns this storage entry (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "user_email": { + "description": "Email address of the owning user. `null` for end-user (user-JWT) callers; populated for developer and server-to-server callers.", + "example": "user@example.com", + "type": "string" + }, + "user_name": { + "description": "Display name of the owning user. `null` for end-user (user-JWT) callers; populated for developer and server-to-server callers.", + "example": "Example Name", + "type": "string" + }, + "value": { + "description": "The string value stored under `key` for this user.", + "example": "dark", + "type": "string" + } + }, + "required": [ + "user", + "key", + "value", + "created_at", + "updated_at" + ], + "type": "object" + }, + "KnowledgeSource": { + "description": "A knowledge source that ingests content into the knowledge base. Sources connect to external systems (e.g. Gmail, GitHub) and continuously or on-demand index items for search.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "context_installation": "cin_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "id": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_source": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "payload": { + "key": "value" + }, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "state": "active", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "gmail", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this source (`agt_...`). `null` if owned by a human user or team.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "context_installation": { + "description": "ID of the context installation that provisioned this source (`cin_...`). `null` when the source was created directly rather than through an installation.", + "example": "cin_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When this knowledge source was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Knowledge source ID (`cso_...`).", + "example": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this source. Useful for storing caller-defined labels or references.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization this source belongs to (`org_...`). `null` if not scoped to an org.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent_source": { + "description": "ID of the parent knowledge source (`cso_...`) when this source was derived from another. `null` for top-level sources.", + "example": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "payload": { + "description": "Type-specific configuration object. The keys depend on the source `type`; see the create endpoint for the expected shape per type.", + "example": { + "key": "value" + }, + "type": "object" + }, + "sandbox": { + "description": "ID of the developer sandbox this source is scoped to (`sbx_...`). `null` outside sandbox contexts.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "state": { + "description": "Current lifecycle state of the source. One of `\"active\"` (ingestion running normally) or `\"paused\"` (ingestion suspended).", + "example": "active", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this source (`tea_...`). `null` if owned by a user, agent, or org.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the chat thread this source is associated with (`thr_...`). `null` when not thread-scoped.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "type": { + "description": "Source type identifier (e.g. `\"gmail\"`, `\"github_activity\"`). Determines the shape of `payload` and the ingestion behavior.", + "example": "gmail", + "type": "string" + }, + "updated_at": { + "description": "When this knowledge source was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this source (`usr_...`). `null` if owned by a team, agent, or org.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "type", + "state" + ], + "type": "object" + }, + "KnowledgeSourceKind": { + "description": "Describes a single knowledge source kind that can be created through the public API. Use the `type` value when creating a new knowledge source.", + "example": { + "description": "An example description.", + "label": "Gmail", + "type": "gmail" + }, + "properties": { + "description": { + "description": "Short description of what this source kind ingests and how it is used.", + "example": "An example description.", + "type": "string" + }, + "label": { + "description": "Human-readable display name for this source kind, suitable for showing in a UI.", + "example": "Gmail", + "type": "string" + }, + "type": { + "description": "Machine-readable type identifier for this source kind (e.g. `\"gmail\"`, `\"github_activity\"`). Pass this value as `type` when creating a knowledge source.", + "example": "gmail", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "KnowledgeSourceKindListResponse": { + "description": "List response containing the knowledge source kinds available for creation via the API.", + "example": { + "data": [ + { + "description": "An example description.", + "label": "Gmail", + "type": "gmail" + } + ] + }, + "properties": { + "data": { + "description": "Array of knowledge source kind objects describing each creatable source type.", + "items": { + "$ref": "#/components/schemas/KnowledgeSourceKind" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "LLMConfig": { + "description": "LLM invocation settings for a routine or chain step. When present, overrides the agent-level model selection.", + "example": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "properties": { + "model": { + "description": "Provider-prefixed model identifier for this routine or step, e.g. `\"openrouter/anthropic/claude-sonnet-latest\"`. When omitted, the agent's default model is used.", + "example": "openrouter/anthropic/claude-sonnet-latest", + "type": "string" + } + }, + "type": "object" + }, + "MediaVariant": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "$ref": "#/components/schemas/ImageSource", + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types." + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "Message": { + "description": "A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "$ref": "#/components/schemas/Acl", + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else." + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "items": { + "$ref": "#/components/schemas/Actor" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "items": { + "$ref": "#/components/schemas/Attachment" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "items": { + "$ref": "#/components/schemas/MessageReaction" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "MessagePolicy": { + "description": "Controls visibility and canonical recipient selection for routine-emitted messages.\n", + "example": { + "recipients": [ + "routine_owner", + "run_actor" + ], + "visibility": "private" + }, + "properties": { + "recipients": { + "description": "Required and non-empty for private visibility. Sources are additive. Routine owner includes the agent owner and optional user co-owner.", + "example": [ + "routine_owner", + "run_actor" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "visibility": { + "description": "Message visibility. One of `default` or `private`.", + "example": "private", + "type": "string" + } + }, + "type": "object" + }, + "MessageReaction": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "Notification": { + "description": "An inbox notification delivered to a recipient user. Includes type-specific render data resolved at request time.", + "example": { + "archived_at": "2024-01-01T00:00:00Z", + "created_at": "2024-01-01T00:00:00Z", + "id": "ntf_0aBcDeFgHiJkLmNoPqRsTu", + "read_at": "2024-01-01T00:00:00Z", + "rendered": {}, + "status": "unread", + "type": "app_info" + }, + "properties": { + "archived_at": { + "description": "When the recipient archived this notification. `null` if the notification has not been archived.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_at": { + "description": "When the notification was sent (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Notification ID (`ntf_...`).", + "example": "ntf_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "read_at": { + "description": "When the recipient marked this notification read. `null` if the notification has not been read.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "rendered": { + "description": "Type-specific render spec resolved at request time. All types include `title`, `kind`, and `actions`; custom types may add their own keys. Notifications whose type is no longer registered render with `kind: \"unknown\"`.", + "example": {}, + "type": "object" + }, + "status": { + "description": "Current read state of the notification. One of `\"unread\"`, `\"read\"`, or `\"archived\"`.", + "example": "unread", + "type": "string" + }, + "type": { + "description": "Notification type slug, e.g. `\"app_info\"` for a built-in type or `\"custom:deploy_complete\"` for a custom type.", + "example": "app_info", + "type": "string" + } + }, + "required": [ + "id", + "type", + "status", + "rendered", + "created_at" + ], + "type": "object" + }, + "NotificationPreference": { + "description": "A single per-channel notification preference for the authenticated viewer, scoped to a notification type and optional app.", + "example": { + "app_id": "string", + "channel": "email", + "created_at": "2024-01-01T00:00:00Z", + "enabled": true, + "id": "string", + "type": "app_info", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "app_id": { + "description": "App this preference is scoped to (`app_...`). `null` indicates a system-level (no-app) slot that applies across all apps.", + "example": "string", + "type": "string" + }, + "channel": { + "description": "Delivery channel for this preference, e.g. `\"email\"`. The `in_app` channel is always active and never has a preference row.", + "example": "email", + "type": "string" + }, + "created_at": { + "description": "When this preference record was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "enabled": { + "description": "Whether delivery over this channel is enabled for the given type-and-app combination. `false` suppresses delivery even when the notification is triggered.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Preference record ID (`ntfp_...`).", + "example": "string", + "type": "string" + }, + "type": { + "description": "Notification type in wire-format. Built-in types use their atom name, e.g. `\"app_info\"` or `\"billing_alert\"`. Custom notification types use the form `\"custom:\"`.", + "example": "app_info", + "type": "string" + }, + "updated_at": { + "description": "When this preference record was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "type", + "channel", + "enabled" + ], + "type": "object" + }, + "NotificationPreferenceList": { + "description": "The complete set of notification preferences belonging to the authenticated viewer.", + "example": { + "data": [ + { + "app_id": "string", + "channel": "email", + "created_at": "2024-01-01T00:00:00Z", + "enabled": true, + "id": "string", + "type": "app_info", + "updated_at": "2024-01-01T00:00:00Z" + } + ] + }, + "properties": { + "data": { + "description": "Array of notification preference objects for the authenticated viewer. Each entry corresponds to a distinct type-and-channel combination.", + "items": { + "$ref": "#/components/schemas/NotificationPreference" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "OAuthTokenResponse": { + "description": "A successful OAuth 2.0 token response. Issued by the token endpoint after a completed authorization or device-flow grant.", + "example": { + "access_token": "string", + "expires_in": 3600, + "refresh_token": "string", + "scope": "read write", + "token_type": "Bearer", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + }, + "properties": { + "access_token": { + "description": "Bearer token used to authenticate API requests. Include this value in the `Authorization: Bearer ` header.", + "example": "string", + "type": "string", + "x-sdk": "access_token" + }, + "expires_in": { + "description": "Number of seconds until the access token expires.", + "example": 3600, + "type": "integer", + "x-sdk": "token_expiry" + }, + "refresh_token": { + "description": "Token that can be exchanged for a new access token once the current one expires. `null` if the grant type does not issue refresh tokens.", + "example": "string", + "type": "string", + "x-sdk": "refresh_token" + }, + "scope": { + "description": "Space-separated list of scopes granted to the access token. `null` if scope was not included in the grant request.", + "example": "read write", + "type": "string" + }, + "token_type": { + "description": "Token type. Always `\"Bearer\"`.", + "example": "Bearer", + "type": "string" + }, + "user": { + "$ref": "#/components/schemas/User", + "description": "The authenticated user associated with this token. `null` when the token is not tied to a specific user (e.g. client-credentials grants)." + } + }, + "required": [ + "access_token", + "token_type", + "expires_in" + ], + "type": "object" + }, + "PaginatedReplies": { + "description": "A paginated list of reply messages for a thread. The reply array is returned directly, not nested inside a `data` wrapper.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "has_more": true, + "replies": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ], + "total_count": 42 + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor to pass as the pagination cursor to retrieve the page of replies that follow this one. `null` when no further pages exist.", + "example": "string", + "type": "string" + }, + "before_cursor": { + "description": "Opaque cursor to pass as the pagination cursor to retrieve the page of replies that precede this one. `null` when no earlier pages exist.", + "example": "string", + "type": "string" + }, + "has_more": { + "description": "Whether additional reply pages exist beyond the current page.", + "example": true, + "type": "boolean" + }, + "replies": { + "description": "Array of reply message objects for the current page.", + "items": { + "$ref": "#/components/schemas/Message" + }, + "type": "array" + }, + "total_count": { + "description": "Total number of replies in the thread across all pages.", + "example": 42, + "type": "integer" + } + }, + "required": [ + "replies" + ], + "type": "object" + }, + "PresetConfig": { + "description": "Configuration for a preset routine handler. Controls the agent's behavior, session persistence, and model selection for a given routine or chain step.", + "example": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "properties": { + "instructions": { + "description": "Custom task or behavior instructions for the preset (max 10,000 chars).", + "example": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "type": "string" + }, + "llm": { + "$ref": "#/components/schemas/LLMConfig", + "description": "LLM invocation settings (e.g. a `model` override for this routine/step)." + }, + "session_mode": { + "description": "Session mode: `stateless` (default, new session per trigger) or `session` (find-or-create a persistent session scoped by `session_scope`).", + "example": "stateless", + "type": "string" + }, + "session_scope": { + "description": "When `session_mode` is `session`, controls session scoping: `per_user` (default), `per_key`, `per_org`, or `global`.", + "example": "per_user", + "type": "string" + }, + "structured_message_template_ids": { + "description": "IDs of structured message templates that constrain the agent's responses to predefined structured formats.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "PrivateService": { + "description": "An immutable private service with complete callable operation contracts.", + "example": { + "functions": [ + { + "description": "An example description.", + "input_schema": {}, + "name": "Example Name", + "output_schema": {} + } + ], + "id": "string" + }, + "properties": { + "functions": { + "description": "Sorted callable definitions exposed by this private service.", + "items": { + "$ref": "#/components/schemas/PrivateServiceFunction" + }, + "type": "array" + }, + "id": { + "description": "Private service ID (`pvs_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "functions" + ], + "type": "object" + }, + "PrivateServiceEnrollment": { + "description": "A private service's durable connector identity. Read responses never contain\nan enrollment token or certificate.\n", + "example": { + "generation": 1, + "id": "string", + "private_service": "string" + }, + "properties": { + "generation": { + "description": "Latest committed connector certificate generation, or zero before enrollment.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Canonical certificate-bound service identity.", + "example": "string", + "type": "string" + }, + "private_service": { + "description": "Immutable private service ID (`pvs_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "private_service", + "generation" + ], + "type": "object" + }, + "PrivateServiceEnrollmentPage": { + "description": "A secret-free page of private service enrollments.", + "example": { + "data": [ + { + "generation": 1, + "id": "string", + "private_service": "string" + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 1, + "total_entries": 1, + "total_pages": 1 + }, + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/PrivateServiceEnrollment" + }, + "type": "array" + }, + "has_next": { + "example": true, + "type": "boolean" + }, + "has_prev": { + "example": true, + "type": "boolean" + }, + "page": { + "example": 1, + "type": "integer" + }, + "page_size": { + "example": 1, + "type": "integer" + }, + "total_entries": { + "example": 1, + "type": "integer" + }, + "total_pages": { + "example": 1, + "type": "integer" + } + }, + "required": [ + "data", + "page", + "page_size", + "total_entries", + "total_pages", + "has_next", + "has_prev" + ], + "type": "object" + }, + "PrivateServiceFunction": { + "description": "A documented callable operation exposed by a private service.", + "example": { + "description": "An example description.", + "input_schema": {}, + "name": "Example Name", + "output_schema": {} + }, + "properties": { + "description": { + "description": "Human-readable guidance describing when and why to call the operation.", + "example": "An example description.", + "type": "string" + }, + "input_schema": { + "description": "JSON Schema Draft 7 object describing the operation's argument object.", + "example": {}, + "type": "object" + }, + "name": { + "description": "Stable operation name used when invoking the private service.", + "example": "Example Name", + "type": "string" + }, + "output_schema": { + "description": "Optional JSON Schema Draft 7 object describing the successful result.", + "example": {}, + "type": "object" + } + }, + "required": [ + "name", + "description", + "input_schema" + ], + "type": "object" + }, + "PrivateServicePage": { + "description": "A page of private services.", + "example": { + "data": [ + { + "functions": [ + { + "description": "An example description.", + "input_schema": {}, + "name": "Example Name", + "output_schema": {} + } + ], + "id": "string" + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 1, + "total_entries": 1, + "total_pages": 1 + }, + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/PrivateService" + }, + "type": "array" + }, + "has_next": { + "example": true, + "type": "boolean" + }, + "has_prev": { + "example": true, + "type": "boolean" + }, + "page": { + "example": 1, + "type": "integer" + }, + "page_size": { + "example": 1, + "type": "integer" + }, + "total_entries": { + "example": 1, + "type": "integer" + }, + "total_pages": { + "example": 1, + "type": "integer" + } + }, + "required": [ + "data", + "page", + "page_size", + "total_entries", + "total_pages", + "has_next", + "has_prev" + ], + "type": "object" + }, + "RoutinePreset": { + "description": "A named preset that defines the execution model and constraints for a routine. Presets are shared definitions; individual routines reference a preset by name.", + "example": { + "applicable_events": [ + "string" + ], + "chainable": true, + "description": "An example description.", + "label": "string", + "name": "Example Name", + "sessionable": true, + "unique": true + }, + "properties": { + "applicable_events": { + "description": "Event types that routines using this preset may be triggered by. `[\"*\"]` means the preset accepts any event type. Routines assigned to this preset will be rejected at creation time if their trigger event is not in this list.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "chainable": { + "description": "Whether routines using this preset can be composed as a step inside a chain routine. Presets with sessionable or asynchronous execution models are not chainable.", + "example": true, + "type": "boolean" + }, + "description": { + "description": "Human-readable description of what the preset does and when to use it.", + "example": "An example description.", + "type": "string" + }, + "label": { + "description": "Human-readable display name for the preset, suitable for use in UIs.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Stable machine identifier for the preset, e.g. `\"do_task\"`. Used when assigning a preset to a routine.", + "example": "Example Name", + "type": "string" + }, + "sessionable": { + "description": "Whether the preset runs inside the thread conversation-session lifecycle. This is distinct from preset_config.session_mode, which controls durable session reuse for do_task and send_message.", + "example": true, + "type": "boolean" + }, + "unique": { + "description": "Whether at most one routine with this preset may exist per agent. Attempting to create a second routine with a unique preset on the same agent will be rejected.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "name", + "label", + "description", + "applicable_events", + "sessionable", + "unique", + "chainable" + ], + "type": "object" + }, + "RunJournalPage": { + "description": "A forward-paginated journal entry page for an automation or routine run.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "command_id": "string", + "created_at": "2024-01-01T00:00:00Z", + "id": "wdr_0aBcDeFgHiJkLmNoPqRsTu", + "node_id": "string", + "record": {}, + "sequence": 1, + "timer_id": "string", + "type": "string" + } + ], + "has_more": true, + "journal": { + "completed_at": "2024-01-01T00:00:00Z", + "created_at": "2024-01-01T00:00:00Z", + "current_sequence": 1, + "id": "wde_0aBcDeFgHiJkLmNoPqRsTu", + "started_at": "2024-01-01T00:00:00Z", + "status": "string", + "updated_at": "2024-01-01T00:00:00Z" + } + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor for the next entry page. `null` when this is the final page.", + "example": "string", + "type": "string" + }, + "before_cursor": { + "description": "Always `null`; journal pagination is forward-only.", + "example": "string", + "type": "string" + }, + "data": { + "description": "Journal entries ordered by ascending sequence. Empty when the run has no journal.", + "items": { + "$ref": "#/components/schemas/WorkflowJournalEntry" + }, + "type": "array" + }, + "has_more": { + "description": "Whether additional entries exist after this page.", + "example": true, + "type": "boolean" + }, + "journal": { + "$ref": "#/components/schemas/WorkflowJournal", + "description": "Durable execution summary. `null` when this run has no journal, which is valid for script-backed, preview, or legacy runs." + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + }, + "Sandbox": { + "description": "An isolated developer sandbox environment used for testing integrations without affecting production data or sending real emails.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "expires_at": "2024-01-01T00:00:00Z", + "id": "string", + "keys": [ + { + "created_at": "2024-01-01T00:00:00Z", + "expires_at": "2024-01-01T00:00:00Z", + "full_key": "string", + "id": "dsk_0aBcDeFgHiJkLmNoPqRsTu", + "key_hint": "Xk9q", + "key_value": "string", + "last_used_at": "2024-01-01T00:00:00Z", + "status": "active", + "type": "publishable" + } + ], + "name": "Example Name", + "org": "string", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "purpose": "string", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "created_at": { + "description": "When this sandbox was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "expires_at": { + "description": "When an eval sandbox expires and becomes eligible for platform cleanup. `null` for ordinary developer sandboxes.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Sandbox ID (`dsb_...`).", + "example": "string", + "type": "string" + }, + "keys": { + "description": "API keys associated with this sandbox. `null` if keys were not loaded with this response.", + "items": { + "$ref": "#/components/schemas/SandboxKey" + }, + "type": "array" + }, + "name": { + "description": "Human-readable display name for the sandbox.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID this sandbox is scoped to, or `null` for an app-level sandbox.", + "example": "string", + "type": "string" + }, + "org_logo": { + "$ref": "#/components/schemas/ImageSource", + "description": "Logo of the owning organization, when present." + }, + "org_name": { + "description": "Display name of the owning organization, when org-scoped.", + "example": "Example Name", + "type": "string" + }, + "purpose": { + "description": "Sandbox purpose marker. `\"eval\"` marks a remote-eval sandbox; `null` for ordinary developer sandboxes.", + "example": "string", + "type": "string" + }, + "slug": { + "description": "URL-safe identifier for the sandbox, unique within the application (e.g. `\"my-sandbox\"`).", + "example": "example-slug", + "type": "string" + }, + "updated_at": { + "description": "When this sandbox was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "name", + "slug" + ], + "type": "object" + }, + "SandboxKey": { + "description": "An API key scoped to a developer sandbox, used to authenticate requests against sandbox resources.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "expires_at": "2024-01-01T00:00:00Z", + "full_key": "string", + "id": "dsk_0aBcDeFgHiJkLmNoPqRsTu", + "key_hint": "Xk9q", + "key_value": "string", + "last_used_at": "2024-01-01T00:00:00Z", + "status": "active", + "type": "publishable" + }, + "properties": { + "created_at": { + "description": "When this key was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "expires_at": { + "description": "When this key expires and becomes invalid. `null` if the key does not expire.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "full_key": { + "description": "The complete secret key value, returned only once when the key is first created. `null` on subsequent retrievals.", + "example": "string", + "type": "string" + }, + "id": { + "description": "Sandbox key ID (`dsk_...`).", + "example": "dsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "key_hint": { + "description": "A short hint showing the last four characters of the key, used for identification. `null` if no hint is available.", + "example": "Xk9q", + "type": "string" + }, + "key_value": { + "description": "The full key value for `\"publishable\"` keys. `null` for `\"secret\"` keys; use `full_key` instead, which is returned only at creation time.", + "example": "string", + "type": "string" + }, + "last_used_at": { + "description": "When this key was last used to authenticate a request. `null` if the key has never been used.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "status": { + "description": "Current lifecycle status of the key. One of `\"active\"` (usable) or `\"revoked\"` (permanently disabled).", + "example": "active", + "type": "string" + }, + "type": { + "description": "The kind of key. One of `\"publishable\"` (safe for client-side use) or `\"secret\"` (server-side only).", + "example": "publishable", + "type": "string" + } + }, + "required": [ + "id", + "type", + "status" + ], + "type": "object" + }, + "SlackChannelBinding": { + "description": "A binding that connects a Slack channel to an ArchAstro team and one or more agents, enabling those agents to receive and respond to messages in that channel.", + "example": { + "agents": [ + "string" + ], + "allow_bot_conversations": true, + "channel": "C01234ABCDE", + "customer_label": "string", + "deposit_thread": "string", + "disclosure_state": "pending", + "id": "scb_0aBcDeFgHiJkLmNoPqRsTu", + "integration": "int_0aBcDeFgHiJkLmNoPqRsTu", + "is_ext_shared_cached": true, + "is_private_cached": true, + "mirrors": [ + "string" + ], + "muted": true, + "muted_until": "string", + "reply_style": "string", + "resident_agent": "string", + "route_kind": "fda", + "scope_key": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "vendor_admin_channel_access": "invited" + }, + "properties": { + "agents": { + "description": "IDs of every agent attached to this binding, including legacy concierge attachments. Use `resident_agent` and `route_kind` for the effective runtime route.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "allow_bot_conversations": { + "description": "Whether this channel opts into sustained bot-to-bot conversation, exempting it from the reply loop brake. Defaults to `false`.", + "example": true, + "type": "boolean" + }, + "channel": { + "description": "Slack channel ID (e.g. `C01234ABCDE`) that this binding targets.", + "example": "C01234ABCDE", + "type": "string" + }, + "customer_label": { + "description": "Human-readable label identifying the customer, derived from the binding's embedded config. `null` when not set.", + "example": "string", + "type": "string" + }, + "deposit_thread": { + "description": "Staging thread the deposit pipe copies this channel's mirror content into (`thr_…` public ID). `null` when the pipe is off for this binding.", + "example": "string", + "type": "string" + }, + "disclosure_state": { + "description": "Slack Connect lifecycle: `pending` while the customer has not accepted the invite (nothing mirrors), `posted` once the AI disclosure is in the channel and the channel is live, `suppressed` when relay is stopped. `null` for a binding that never went through Connect provisioning.", + "enum": [ + "pending", + "posted", + "suppressed" + ], + "example": "pending", + "type": "string" + }, + "id": { + "description": "Unique identifier for this Slack channel binding.", + "example": "scb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "integration": { + "description": "ID of the Slack integration that owns this binding.", + "example": "int_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_ext_shared_cached": { + "description": "Cached value of Slack's `is_ext_shared` flag for this channel. May be stale relative to Slack's current state.", + "example": true, + "type": "boolean" + }, + "is_private_cached": { + "description": "Cached value of Slack's `is_private` flag for this channel. May be stale relative to Slack's current state. Private channels are member-managed: mutating the binding requires in-channel evidence.", + "example": true, + "type": "boolean" + }, + "mirrors": { + "description": "IDs of every mirror thread this channel's messages land in (`thr_…` public IDs) that the caller can read, including any legacy peel or chain threads. Empty for a caller with no membership on any of them, and for a channel that has not mirrored anything yet. IDs only: reading a mirror's contents still requires membership on it.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "muted": { + "description": "Whether the resident agent is currently muted. A muted resident keeps mirroring the channel (reading) but stops replying. A timed mute expires automatically at `muted_until`; this reflects the effective state as of now. Defaults to `false`.", + "example": true, + "type": "boolean" + }, + "muted_until": { + "description": "ISO 8601 timestamp when a timed mute expires and replies resume. `null` for an indefinite mute (until an explicit unmute) or when not muted.", + "example": "string", + "type": "string" + }, + "reply_style": { + "description": "How the resident agent's replies post to Slack: `thread` (default) threads a reply under the message that triggered it; `top_level` posts it flat in the channel.", + "example": "string", + "type": "string" + }, + "resident_agent": { + "description": "ID of the resident agent selected by Slack ingress. `null` when no resident is attached and the channel is an observer.", + "example": "string", + "type": "string" + }, + "route_kind": { + "description": "Effective Slack ingress route. `fda` — a resident on a team-bound channel, replying through the Forward Deployed Agent chain. `resident` — a resident on an internal channel, replying through the channel mirror. `observer` — no resident is attached, so the channel is recorded and nobody replies. `concierge` — no longer returned anywhere; until Track F it was the value for a channel with no resident, meaning the shared concierge agent answered there. The value is retained in this enum so consumers matching on it do not break, and its removal rides a deliberate API change.", + "enum": [ + "fda", + "resident", + "observer", + "concierge" + ], + "example": "fda", + "type": "string" + }, + "scope_key": { + "description": "The customer key this channel's agent is locked to, written when adding the customer finishes. A `posted` binding whose `scope_key` is still null has been accepted but not finished — the addition is either in flight or was refused.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the ArchAstro team this channel is bound to.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "vendor_admin_channel_access": { + "description": "Whether the admin who added this customer ended up inside a Connect channel we created for them: `invited` (we put them in), `already_member` (they were in it already), `no_slack_user` (their account email is not a Slack account in your workspace, so nobody was invited), or `failed` (Slack refused). A created Connect channel is private and has no self-join, so the last two mean the channel has no human from your side until someone already in it adds one. `null` when nobody was added: the channel was adopted rather than created (an existing channel already has its own members), the binding never went through Connect provisioning, or the call had no admin behind it.", + "enum": [ + "invited", + "already_member", + "no_slack_user", + "failed" + ], + "example": "invited", + "type": "string" + } + }, + "required": [ + "id", + "route_kind", + "allow_bot_conversations", + "muted", + "reply_style" + ], + "type": "object" + }, + "SlackChannelBindingListResponse": { + "description": "Paginated list of Slack channel bindings for the requested integration or team. Use the `page` and `per_page` fields to navigate pages of results.", + "example": { + "data": [ + { + "agents": [ + "string" + ], + "allow_bot_conversations": true, + "channel": "C01234ABCDE", + "customer_label": "string", + "deposit_thread": "string", + "disclosure_state": "pending", + "id": "scb_0aBcDeFgHiJkLmNoPqRsTu", + "integration": "int_0aBcDeFgHiJkLmNoPqRsTu", + "is_ext_shared_cached": true, + "is_private_cached": true, + "mirrors": [ + "string" + ], + "muted": true, + "muted_until": "string", + "reply_style": "string", + "resident_agent": "string", + "route_kind": "fda", + "scope_key": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "vendor_admin_channel_access": "invited" + } + ], + "page": 1, + "per_page": 20, + "total_count": 1, + "total_pages": 1 + }, + "properties": { + "data": { + "description": "Array of Slack channel binding objects for the current page.", + "items": { + "$ref": "#/components/schemas/SlackChannelBinding" + }, + "type": "array" + }, + "page": { + "description": "Current page number (1-indexed).", + "example": 1, + "type": "integer" + }, + "per_page": { + "description": "Maximum number of bindings returned per page.", + "example": 20, + "type": "integer" + }, + "total_count": { + "description": "Total number of Slack channel bindings matching the query across all pages.", + "example": 1, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages available at the current `per_page` size.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "data", + "page", + "per_page", + "total_count", + "total_pages" + ], + "type": "object" + }, + "SlackDeliveryOutcome": { + "description": "What happened to one agent message this platform sent to a Slack channel. Lets you confirm delivery, or find out why a reply never arrived, without reading the channel's mirrored conversation.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "binding": "scb_0aBcDeFgHiJkLmNoPqRsTu", + "channel": "C01234ABCDE", + "failure_reason": "slack:channel_not_found", + "guard_kind": "RegexMatch", + "guard_labels": [ + "string" + ], + "id": "sdo_0aBcDeFgHiJkLmNoPqRsTu", + "message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "operation": "post", + "outcome": "delivered", + "recorded_at": "2024-01-01T00:00:00Z", + "thread_ts": "string" + }, + "properties": { + "agent": { + "description": "ID of the agent whose message this was.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "binding": { + "description": "ID of the Slack channel binding in force for this send. `null` when no binding could be resolved, in which case the send was treated as cross-org and floored on that basis.", + "example": "scb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "channel": { + "description": "Slack channel ID the send was addressed to.", + "example": "C01234ABCDE", + "type": "string" + }, + "failure_reason": { + "description": "For a `failed` send, a short machine-readable cause — `slack:` when Slack rejected the call, or `floor_config` when the content floor could not be evaluated and the send failed closed.", + "example": "slack:channel_not_found", + "type": "string" + }, + "guard_kind": { + "description": "For a withheld send, the kind of guard that stopped it — `RegexMatch`, `ContainsAny`, `ContainsString`, or `LLMJudge`. `null` when the send was not withheld by a guard.", + "example": "RegexMatch", + "type": "string" + }, + "guard_labels": { + "description": "For a withheld send, the labels of the guards that stopped it (for example `Contains AWS access key ID`). These are the content policy's own descriptions, recorded as they read at the time of the send; they never contain the withheld message.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "id": { + "description": "Unique identifier for this delivery outcome.", + "example": "sdo_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "message": { + "description": "ID of the platform message this attempt was carrying. Reading that message still requires access to its thread — this field correlates, it does not grant.", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "operation": { + "description": "Whether the attempt posted a new Slack message or updated an existing one (replacing a thinking placeholder).", + "enum": [ + "post", + "update" + ], + "example": "post", + "type": "string" + }, + "outcome": { + "description": "What happened to the send. `delivered` — Slack accepted the message. `floored` — a deterministic content guard withheld it, so it never left. `judge_refused` — the cross-org judge decided it was not appropriate for this channel's audience. `failed` — Slack rejected the call, or the content floor could not be evaluated and the send failed closed.", + "enum": [ + "delivered", + "floored", + "judge_refused", + "failed" + ], + "example": "delivered", + "type": "string" + }, + "recorded_at": { + "description": "When the send was attempted.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "thread_ts": { + "description": "Slack thread timestamp the send targeted, letting attempts be grouped into the conversation they belong to. `null` for a top-level channel post.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "outcome", + "operation", + "channel", + "recorded_at" + ], + "type": "object" + }, + "SlackDeliveryOutcomeListResponse": { + "description": "A page of delivery outcomes for one Slack channel, newest first. Page through history with the returned cursors; `since` and `outcome` are filters, not paging controls.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "binding": "scb_0aBcDeFgHiJkLmNoPqRsTu", + "channel": "C01234ABCDE", + "failure_reason": "slack:channel_not_found", + "guard_kind": "RegexMatch", + "guard_labels": [ + "string" + ], + "id": "sdo_0aBcDeFgHiJkLmNoPqRsTu", + "message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "operation": "post", + "outcome": "delivered", + "recorded_at": "2024-01-01T00:00:00Z", + "thread_ts": "string" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor for the page of newer outcomes. Pass back as `after_cursor` to poll for attempts recorded since. `null` when the page is empty.", + "example": "string", + "type": "string" + }, + "before_cursor": { + "description": "Opaque cursor for the page of older outcomes. Pass back as `before_cursor` to continue into history. `null` when the page is empty.", + "example": "string", + "type": "string" + }, + "data": { + "description": "Delivery outcomes matching the query, newest attempt first.", + "items": { + "$ref": "#/components/schemas/SlackDeliveryOutcome" + }, + "type": "array" + }, + "has_more": { + "description": "True when more outcomes exist beyond this page.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + }, + "SolutionAutomationInvokeContract": { + "description": "The schema-driven values an installer may lock when provisioning an invoked automation template.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "items": { + "$ref": "#/components/schemas/AutomationParticipantSlot" + }, + "type": "array" + }, + "prefills": { + "$ref": "#/components/schemas/AutomationPrefills", + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected." + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "SolutionAutomationTemplateDetails": { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "$ref": "#/components/schemas/SolutionAutomationInvokeContract", + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning." + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "SolutionCategoryListResponse": { + "description": "Paginated list of solution category summaries. Use `page` and `page_size` to navigate pages of results.", + "example": { + "data": [ + { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "productivity", + "kind": "SolutionCategory", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owners": [ + "string" + ], + "parent_key": "string", + "sort_order": 1, + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 20, + "total_entries": 42, + "total_pages": 3 + }, + "properties": { + "data": { + "description": "Array of solution category summary objects for the current page.", + "items": { + "$ref": "#/components/schemas/SolutionCategorySummary" + }, + "type": "array" + }, + "has_next": { + "description": "`true` when a subsequent page of results exists.", + "example": true, + "type": "boolean" + }, + "has_prev": { + "description": "`true` when a previous page of results exists.", + "example": true, + "type": "boolean" + }, + "page": { + "description": "Current page number (1-indexed).", + "example": 1, + "type": "integer" + }, + "page_size": { + "description": "Maximum number of entries returned per page.", + "example": 20, + "type": "integer" + }, + "total_entries": { + "description": "Total number of distinct solution categories across all pages.", + "example": 42, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages available at the current `page_size`.", + "example": 3, + "type": "integer" + } + }, + "required": [ + "data", + "page", + "page_size", + "total_entries", + "total_pages", + "has_next", + "has_prev" + ], + "type": "object" + }, + "SolutionCategorySummary": { + "description": "A solution category that organizes solutions in the catalog, identified by a stable key and optionally nested under a parent category.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "productivity", + "kind": "SolutionCategory", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owners": [ + "string" + ], + "parent_key": "string", + "sort_order": 1, + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this category was first created (ISO 8601). `null` for system-built-in categories.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short prose description of what solutions in this category do. `null` when not configured.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Solution category config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "key": { + "description": "Stable, human-readable key for this category, referenced by solutions via `category_keys`.", + "example": "productivity", + "type": "string" + }, + "kind": { + "description": "Resource type identifier. Always `\"SolutionCategory\"`.", + "example": "SolutionCategory", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key of the underlying config record. `null` when not set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this category by the publisher.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Display name shown to users. `null` when not configured.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this category. `null` for system-scoped categories.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owners": { + "description": "Scopes under which this category is visible. Possible values are `\"system\"` (available to all apps) and `\"org\"` (scoped to the viewer's organization).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "parent_key": { + "description": "Key of the parent `SolutionCategory`, enabling a hierarchy. `null` for top-level categories.", + "example": "string", + "type": "string" + }, + "sort_order": { + "description": "Numeric hint for ordering categories in a list. Lower values sort first. `null` when not configured.", + "example": 1, + "type": "integer" + }, + "updated_at": { + "description": "When this category was last modified (ISO 8601). `null` for system-built-in categories.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual path of the underlying config record. `null` when not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "key", + "owners" + ], + "type": "object" + }, + "SolutionDependentAgent": { + "description": "A brief representation of an agent that references at least one config bundled by a Solution, included in the dependents preview response.", + "example": { + "id": "string", + "name": "Example Name" + }, + "properties": { + "id": { + "description": "Agent ID (`agi_...`).", + "example": "string", + "type": "string" + }, + "name": { + "description": "Human-readable display name of the agent. `null` when no name has been set.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "SolutionDependentsResponse": { + "description": "A preview of the agents and configs that would be affected by deleting a Solution, returned before any deletion occurs so the caller can display a confirmation warning.", + "example": { + "dependent_agent_count": 1, + "dependent_agents": [ + { + "id": "string", + "name": "Example Name" + } + ], + "preserved_config_count": 1 + }, + "properties": { + "dependent_agent_count": { + "description": "Total number of distinct agents that reference at least one config bundled by this Solution. Use this count in the confirmation message; `dependent_agents` may be a shorter sample.", + "example": 1, + "type": "integer" + }, + "dependent_agents": { + "description": "A representative sample of the dependent agents, suitable for displaying in a warning list. May contain fewer entries than `dependent_agent_count` when there are many dependents.", + "items": { + "$ref": "#/components/schemas/SolutionDependentAgent" + }, + "type": "array" + }, + "preserved_config_count": { + "description": "Number of bundled configs that would be detached and preserved rather than deleted, because at least one live agent still references them.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "dependent_agent_count", + "dependent_agents", + "preserved_config_count" + ], + "type": "object" + }, + "SolutionDiffEntry": { + "description": "A single config entry in a solution upgrade diff, describing what action will be taken on a specific config key.", + "example": { + "action": "update", + "content_changed": true, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "string", + "kind": "Automation", + "lookup_key": "string", + "mime_type_changed": true, + "referenced_by": [ + { + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "Automation", + "lookup_key": "string", + "reason": "string" + } + ], + "relative_path_changed": true, + "role": "primary", + "virtual_path": "/path/to/resource" + }, + "properties": { + "action": { + "description": "Planned action for this entry. One of `\"add\"` (new config), `\"update\"` (existing config changes), `\"noop\"` (no change needed), `\"orphan\"` (config no longer in the solution), or `\"delete\"` (config to be removed).", + "example": "update", + "type": "string" + }, + "content_changed": { + "description": "`true` if the config content differs between the existing and incoming solution versions.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Config ID (`cfg_...`) if this entry corresponds to an existing config record. `null` for new additions.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "key": { + "description": "Stable string key identifying this config entry within the solution.", + "example": "string", + "type": "string" + }, + "kind": { + "description": "Config object type, e.g. `\"Automation\"` or `\"Template\"`. `null` if not yet known.", + "example": "Automation", + "type": "string" + }, + "lookup_key": { + "description": "Human-readable stable identifier for this config. `null` if not assigned.", + "example": "string", + "type": "string" + }, + "mime_type_changed": { + "description": "`true` if the MIME type of the config changed between versions.", + "example": true, + "type": "boolean" + }, + "referenced_by": { + "description": "List of other configs that reference this entry. Populated for orphaned configs that cannot be safely removed. Empty array when there are no references.", + "items": { + "$ref": "#/components/schemas/SolutionDiffReference" + }, + "type": "array" + }, + "relative_path_changed": { + "description": "`true` if the relative path of the config within the solution changed between versions.", + "example": true, + "type": "boolean" + }, + "role": { + "description": "Role of this config within the solution. Indicates whether it is a primary config or a dependency.", + "example": "primary", + "type": "string" + }, + "virtual_path": { + "description": "Hierarchical path of this config in the config tree. `null` if not assigned.", + "example": "/path/to/resource", + "type": "string" + } + }, + "required": [ + "role", + "action", + "key", + "content_changed", + "mime_type_changed", + "relative_path_changed" + ], + "type": "object" + }, + "SolutionDiffReference": { + "description": "A reference from another config to an orphaned entry in a solution upgrade diff, explaining why the orphan cannot be safely removed.", + "example": { + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "Automation", + "lookup_key": "string", + "reason": "string" + }, + "properties": { + "id": { + "description": "ID of the referencing config (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Object type of the referencing config, e.g. `\"Automation\"` or `\"Template\"`.", + "example": "Automation", + "type": "string" + }, + "lookup_key": { + "description": "Human-readable stable identifier of the referencing config. `null` if not assigned.", + "example": "string", + "type": "string" + }, + "reason": { + "description": "Explanation of how the referencing config depends on the orphaned entry.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "reason" + ], + "type": "object" + }, + "SolutionDiffSummary": { + "description": "Aggregate counts of each action type across all entries in a solution upgrade diff.", + "example": { + "adds": 1, + "deletes": 1, + "noops": 1, + "orphans": 1, + "referenced_orphans": 1, + "updates": 1 + }, + "properties": { + "adds": { + "description": "Number of config entries that will be newly created by this upgrade.", + "example": 1, + "type": "integer" + }, + "deletes": { + "description": "Number of config entries that will be deleted as part of the upgrade.", + "example": 1, + "type": "integer" + }, + "noops": { + "description": "Number of config entries that are already up to date and require no changes.", + "example": 1, + "type": "integer" + }, + "orphans": { + "description": "Number of config entries present in the existing solution that are absent from the incoming version and have no external references blocking removal.", + "example": 1, + "type": "integer" + }, + "referenced_orphans": { + "description": "Number of orphaned config entries that cannot be removed because other configs still reference them.", + "example": 1, + "type": "integer" + }, + "updates": { + "description": "Number of config entries that exist and will be updated with new content.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "adds", + "updates", + "noops", + "orphans", + "deletes", + "referenced_orphans" + ], + "type": "object" + }, + "SolutionImportResponse": { + "description": "The result of importing a Solution bundle into the library, including the Solution config record, a structured import result, and the list of all configs persisted during the transaction.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "import_result": { + "code": "string", + "dry_run": true, + "existing_solution_version": "1.0.0", + "incoming_solution_version": "1.0.0", + "message": "string", + "status": "ready", + "upgrade_required": true, + "warnings": [ + { + "code": "setup_requirements_dropped", + "message": "string", + "path": "templates[0] (agents/support.yaml)" + } + ] + }, + "installed_configs": [ + { + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "my-skill", + "kind": "Skill", + "lookup_key": "my-skill" + } + ], + "kind": "Solution", + "lookup_key": "string", + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When the Solution config record was first created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "import_result": { + "$ref": "#/components/schemas/SolutionImportResult", + "description": "Structured outcome of the import, including status, conflict details, and version information." + }, + "installed_configs": { + "description": "Deprecated legacy field. One entry per persisted config in the import (including the Solution itself), defaulting to an empty array. Callers should prefer `solution` plus follow-up APIs instead. `key` echoes the caller-supplied input identifier (original lookup_key for top-level configs; `:` for skill / solution-file children). Order is stable: sorted by `key`.", + "items": { + "$ref": "#/components/schemas/InstalledConfigEntry" + }, + "type": "array" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "lookup_key": { + "description": "The `lookup_key` stored on the Solution config after the import's suffix normalization. `null` when the Solution was not given a lookup key.", + "example": "string", + "type": "string" + }, + "solution": { + "$ref": "#/components/schemas/SolutionSummary", + "description": "Full summary of the imported Solution, in the same shape as the individual Solution retrieval endpoint." + }, + "updated_at": { + "description": "When the Solution config record was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "The `virtual_path` stored on the Solution config, used as the stable dedupe key across owner scopes. `null` when no virtual path was assigned.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "solution", + "import_result" + ], + "type": "object" + }, + "SolutionImportResult": { + "description": "The machine-readable outcome of a Solution import attempt, indicating whether the import succeeded or requires an upgrade flow to resolve a version conflict.", + "example": { + "code": "string", + "dry_run": true, + "existing_solution_version": "1.0.0", + "incoming_solution_version": "1.0.0", + "message": "string", + "status": "ready", + "upgrade_required": true, + "warnings": [ + { + "code": "setup_requirements_dropped", + "message": "string", + "path": "templates[0] (agents/support.yaml)" + } + ] + }, + "properties": { + "code": { + "description": "Machine-readable conflict code present when `status` is `\"conflict\"`, identifying the specific conflict reason. `null` when `status` is `\"ready\"`.", + "example": "string", + "type": "string" + }, + "dry_run": { + "description": "Whether this result was produced by a dry-run check. `true` when the import was validated without persisting any changes.", + "example": true, + "type": "boolean" + }, + "existing_solution_version": { + "description": "Semver string of the Solution version already present in the library. `null` when no prior version exists.", + "example": "1.0.0", + "type": "string" + }, + "incoming_solution_version": { + "description": "Semver string of the Solution version in the bundle being imported. `null` when the bundle does not declare a version.", + "example": "1.0.0", + "type": "string" + }, + "message": { + "description": "Human-readable description of the import status or conflict reason, suitable for display in a confirmation dialog. `null` when no detail is available.", + "example": "string", + "type": "string" + }, + "status": { + "description": "Outcome of the import check. `\"ready\"` means the import can proceed as a normal create or update. `\"conflict\"` means a version conflict was detected and the upgrade flow must be used instead.", + "example": "ready", + "type": "string" + }, + "upgrade_required": { + "description": "Whether the caller must invoke the dedicated upgrade flow to complete the import. Mirrors `status == \"conflict\"` as a convenience boolean.", + "example": true, + "type": "boolean" + }, + "warnings": { + "description": "Non-fatal findings the import proceeded despite (present on real imports and dry-runs alike; defaults to an empty array). Dry-run validation callers should surface these — or treat them as failures — before applying the real import.", + "items": { + "$ref": "#/components/schemas/SolutionImportWarning" + }, + "type": "array" + } + }, + "required": [ + "status", + "dry_run", + "upgrade_required" + ], + "type": "object" + }, + "SolutionImportWarning": { + "description": "A non-fatal finding surfaced by a Solution import. The import proceeds despite warnings; validation callers (dry-run) can choose to treat them as failures.", + "example": { + "code": "setup_requirements_dropped", + "message": "string", + "path": "templates[0] (agents/support.yaml)" + }, + "properties": { + "code": { + "description": "Machine-readable warning code. `\"setup_requirements_dropped\"`: a template or config body declares catalog-DSL `setup_requirements` that direct import does not convert — installs read only `setup_actions`, so those setup steps would never surface.", + "example": "setup_requirements_dropped", + "type": "string" + }, + "message": { + "description": "Human-readable explanation of the warning and how to resolve it.", + "example": "string", + "type": "string" + }, + "path": { + "description": "Which bundle entry the warning is about, as `[] ()`.", + "example": "templates[0] (agents/support.yaml)", + "type": "string" + } + }, + "required": [ + "code", + "path", + "message" + ], + "type": "object" + }, + "SolutionInstallResponse": { + "description": "The runtime resource provisioned by installing a Solution, along with a reference back to the source Solution config.", + "example": { + "id": "string", + "kind": "Agent", + "lookup_key": "string", + "solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "webhook": { + "signing_secret": "string", + "url": "https://example.com" + } + }, + "properties": { + "id": { + "description": "Public ID of the provisioned resource. The prefix reflects the resource kind: `agi_...` for Agent, `aut_...` for Automation, `art_...` for AgentRoutine, `att_...` for AgentTool, `ask_...` for AgentSkill, `cmp_...` for AgentComputer.", + "example": "string", + "type": "string" + }, + "kind": { + "description": "Type of the provisioned resource. One of `\"Agent\"`, `\"Automation\"`, `\"AgentRoutine\"`, `\"AgentTool\"`, `\"AgentSkill\"`, or `\"AgentComputer\"`.", + "example": "Agent", + "type": "string" + }, + "lookup_key": { + "description": "The `lookup_key` stamped on the provisioned resource. `null` for `AgentSkill`, which is a join record and does not carry a lookup key.", + "example": "string", + "type": "string" + }, + "solution": { + "description": "Solution config ID (`cfg_...`) that was used as the source for this install.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "webhook": { + "$ref": "#/components/schemas/SolutionInstallResponseWebhook", + "description": "One-time connection details for a webhook-auth Automation install." + } + }, + "required": [ + "id", + "kind", + "solution" + ], + "type": "object" + }, + "SolutionInstallResponseWebhook": { + "description": "One-time connection details for a webhook-auth Automation install.", + "example": { + "signing_secret": "string", + "url": "https://example.com" + }, + "properties": { + "signing_secret": { + "example": "string", + "type": "string" + }, + "url": { + "example": "https://example.com", + "type": "string" + } + }, + "required": [ + "url", + "signing_secret" + ], + "type": "object" + }, + "SolutionInstance": { + "description": "A customer-keyed instance stamped from an installed solution template.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_name": "Example Name", + "attachment_ref": {}, + "created_at": "2024-01-01T00:00:00Z", + "customer_key": "string", + "customer_label": "string", + "id": "sli_0aBcDeFgHiJkLmNoPqRsTu", + "local_edit_count": 1, + "pinned_template_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "pinned_version_number": 1, + "solution_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "status": "active", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "agent": { + "description": "Materialized agent for this customer (`agi_...`). `null` for a row without an agent.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_name": { + "description": "Human-readable display name of the materialized agent. `null` when no agent is visible.", + "example": "Example Name", + "type": "string" + }, + "attachment_ref": { + "description": "Opaque tagged reference to the deployment target. Consumers interpret its kind.", + "example": {}, + "type": "object" + }, + "created_at": { + "description": "When this instance was stamped.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "customer_key": { + "description": "Stable vendor-defined key for the customer.", + "example": "string", + "type": "string" + }, + "customer_label": { + "description": "Human-readable customer label. `null` when the vendor did not provide one.", + "example": "string", + "type": "string" + }, + "id": { + "description": "Solution instance ID (`sli_...`).", + "example": "sli_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "local_edit_count": { + "description": "Count of local agent edits relative to the pinned template. `null` when unavailable.", + "example": 1, + "type": "integer" + }, + "pinned_template_version": { + "description": "Pinned template version record (`cfv_...`). `null` when no version is pinned.", + "example": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "pinned_version_number": { + "description": "Human-readable version number of the pinned template. `null` when unavailable.", + "example": 1, + "type": "integer" + }, + "solution_template_config": { + "description": "Installed solution template config that stamped this instance (`cfg_...`).", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Lifecycle status of this stamped instance.", + "enum": [ + "active", + "archived" + ], + "example": "active", + "type": "string" + }, + "updated_at": { + "description": "When this instance was last updated.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "solution_template_config", + "customer_key", + "status", + "created_at", + "updated_at" + ], + "type": "object" + }, + "SolutionInstanceListResponse": { + "description": "A forward cursor-paginated page of customer solution instances.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_name": "Example Name", + "attachment_ref": {}, + "created_at": "2024-01-01T00:00:00Z", + "customer_key": "string", + "customer_label": "string", + "id": "sli_0aBcDeFgHiJkLmNoPqRsTu", + "local_edit_count": 1, + "pinned_template_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "pinned_version_number": 1, + "solution_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "status": "active", + "updated_at": "2024-01-01T00:00:00Z" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor for the next page. `null` when this is the final page.", + "example": "string", + "type": "string" + }, + "before_cursor": { + "description": "Always `null`; this endpoint supports forward pagination only.", + "example": "string", + "type": "string" + }, + "data": { + "description": "Customer solution instances in stable customer-key order.", + "items": { + "$ref": "#/components/schemas/SolutionInstance" + }, + "type": "array" + }, + "has_more": { + "description": "Whether another page exists after this one.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + }, + "SolutionListResponse": { + "description": "A paginated collection of Solution summaries, with page metadata for navigating the result set.", + "example": { + "data": [ + { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 20, + "total_entries": 42, + "total_pages": 3 + }, + "properties": { + "data": { + "description": "Array of Solution summary objects for the current page, in the order returned by the query.", + "items": { + "$ref": "#/components/schemas/SolutionSummary" + }, + "type": "array" + }, + "has_next": { + "description": "`true` when a subsequent page exists; `false` when this is the last page.", + "example": true, + "type": "boolean" + }, + "has_prev": { + "description": "`true` when a preceding page exists; `false` when this is the first page.", + "example": true, + "type": "boolean" + }, + "page": { + "description": "1-based index of the current page.", + "example": 1, + "type": "integer" + }, + "page_size": { + "description": "Maximum number of results included per page.", + "example": 20, + "type": "integer" + }, + "total_entries": { + "description": "Total number of Solutions matching the query after deduplication by `solution_id` across owner scopes.", + "example": 42, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages available at the current `page_size`.", + "example": 3, + "type": "integer" + } + }, + "required": [ + "data", + "page", + "page_size", + "total_entries", + "total_pages", + "has_next", + "has_prev" + ], + "type": "object" + }, + "SolutionSummary": { + "description": "A catalog entry for an imported Solution, including its display metadata, bundled templates, owner scopes, and any available upgrade information.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "$ref": "#/components/schemas/ImageSource", + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo." + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "$ref": "#/components/schemas/SolutionTemplateSummary" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "SolutionTagListResponse": { + "description": "Paginated list of solution tag summaries returned by the list solution tags endpoint.", + "example": { + "data": [ + { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "featured", + "kind": "SolutionTag", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owners": [ + "string" + ], + "sort_order": 1, + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 20, + "total_entries": 42, + "total_pages": 3 + }, + "properties": { + "data": { + "description": "Array of solution tag objects for the current page.", + "items": { + "$ref": "#/components/schemas/SolutionTagSummary" + }, + "type": "array" + }, + "has_next": { + "description": "`true` if a subsequent page exists; `false` when this is the last page.", + "example": true, + "type": "boolean" + }, + "has_prev": { + "description": "`true` if a preceding page exists; `false` when this is the first page.", + "example": true, + "type": "boolean" + }, + "page": { + "description": "Current page number (1-indexed).", + "example": 1, + "type": "integer" + }, + "page_size": { + "description": "Maximum number of results returned per page.", + "example": 20, + "type": "integer" + }, + "total_entries": { + "description": "Total number of distinct solution tags across all pages, after deduplication by key.", + "example": 42, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages available at the current `page_size`.", + "example": 3, + "type": "integer" + } + }, + "required": [ + "data", + "page", + "page_size", + "total_entries", + "total_pages", + "has_next", + "has_prev" + ], + "type": "object" + }, + "SolutionTagSummary": { + "description": "A single solution tag definition, representing a named classification label that can be applied to solutions.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "featured", + "kind": "SolutionTag", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owners": [ + "string" + ], + "sort_order": 1, + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When the solution tag was first created (ISO 8601). `null` if unavailable.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short prose explanation of what the tag represents. `null` if not provided.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Solution tag config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "key": { + "description": "Stable string key for this tag, referenced by `Solution.tag_keys` to associate solutions with this tag.", + "example": "featured", + "type": "string" + }, + "kind": { + "description": "Object type discriminator. Always `\"SolutionTag\"`.", + "example": "SolutionTag", + "type": "string" + }, + "lookup_key": { + "description": "Human-readable stable identifier for this tag config, used for lookups and imports. `null` if not assigned.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this tag. Empty object `{}` when no metadata is present.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the tag. `null` if not yet set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization that owns this tag (`org_...`). `null` for system-scoped tags.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owners": { + "description": "Scopes under which this tag is visible to the caller. One or both of `\"system\"` (platform-level tag available to all orgs) and `\"org\"` (tag scoped to the viewer's org).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "sort_order": { + "description": "Optional integer hint for ordering tags in UI lists. Lower values sort first. `null` if not set.", + "example": 1, + "type": "integer" + }, + "updated_at": { + "description": "When the solution tag was last modified (ISO 8601). `null` if unavailable.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Hierarchical path used to organize this tag in the config tree. `null` if not assigned.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "key", + "owners" + ], + "type": "object" + }, + "SolutionTemplateDetails": { + "description": "Template-kind-specific Solution summary details, discriminated by `type`.", + "discriminator": { + "mapping": { + "automation": "#/components/schemas/SolutionAutomationTemplateDetails" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/SolutionAutomationTemplateDetails" + } + ] + }, + "SolutionTemplateSummary": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "$ref": "#/components/schemas/SolutionTemplateDetails", + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details." + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "SolutionUpgradeResponse": { + "description": "Response returned by the solution upgrade endpoint, containing the solution record, the full upgrade diff, and the resulting installed configs.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "installed_configs": [ + { + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "my-skill", + "kind": "Skill", + "lookup_key": "my-skill" + } + ], + "kind": "Solution", + "lookup_key": "string", + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_result": { + "changes": [ + { + "action": "update", + "content_changed": true, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "string", + "kind": "Automation", + "lookup_key": "string", + "mime_type_changed": true, + "referenced_by": [ + { + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "Automation", + "lookup_key": "string", + "reason": "string" + } + ], + "relative_path_changed": true, + "role": "primary", + "virtual_path": "/path/to/resource" + } + ], + "code": "review_required", + "dry_run": true, + "existing_solution_version": "1.0.0", + "incoming_solution_version": "1.0.0", + "message": "string", + "review_fingerprint": "string", + "status": "ready", + "summary": { + "adds": 1, + "deletes": 1, + "noops": 1, + "orphans": 1, + "referenced_orphans": 1, + "updates": 1 + }, + "version_change": "upgrade" + }, + "virtual_path": "/path/to/resource" + }, + "properties": { + "created_at": { + "description": "When the solution config record was first created (ISO 8601). `null` if unavailable.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Config ID of the solution record (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "installed_configs": { + "description": "List of config entries that were installed or updated as part of this upgrade. Empty when `dry_run` is `true` or when no configs changed.", + "items": { + "$ref": "#/components/schemas/InstalledConfigEntry" + }, + "type": "array" + }, + "kind": { + "description": "Object type discriminator. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "lookup_key": { + "description": "Human-readable stable identifier for this solution config. `null` if not assigned.", + "example": "string", + "type": "string" + }, + "solution": { + "$ref": "#/components/schemas/SolutionSummary", + "description": "Summary of the solution being upgraded, including its name, manifest metadata, and tag keys." + }, + "updated_at": { + "description": "When the solution config record was last modified (ISO 8601). `null` if unavailable.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_result": { + "$ref": "#/components/schemas/SolutionUpgradeResult", + "description": "Detailed result of the upgrade operation, including the computed diff and any conflict information." + }, + "virtual_path": { + "description": "Hierarchical path of the solution in the config tree. `null` if not assigned.", + "example": "/path/to/resource", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "solution", + "upgrade_result" + ], + "type": "object" + }, + "SolutionUpgradeResult": { + "description": "The outcome of a solution upgrade operation, including the computed diff and conflict status.", + "example": { + "changes": [ + { + "action": "update", + "content_changed": true, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "key": "string", + "kind": "Automation", + "lookup_key": "string", + "mime_type_changed": true, + "referenced_by": [ + { + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "Automation", + "lookup_key": "string", + "reason": "string" + } + ], + "relative_path_changed": true, + "role": "primary", + "virtual_path": "/path/to/resource" + } + ], + "code": "review_required", + "dry_run": true, + "existing_solution_version": "1.0.0", + "incoming_solution_version": "1.0.0", + "message": "string", + "review_fingerprint": "string", + "status": "ready", + "summary": { + "adds": 1, + "deletes": 1, + "noops": 1, + "orphans": 1, + "referenced_orphans": 1, + "updates": 1 + }, + "version_change": "upgrade" + }, + "properties": { + "changes": { + "description": "Ordered list of individual config change entries representing every add, update, noop, orphan, and delete in the diff.", + "items": { + "$ref": "#/components/schemas/SolutionDiffEntry" + }, + "type": "array" + }, + "code": { + "description": "Machine-readable conflict code when `status` is `\"conflict\"`, e.g. `\"review_required\"`. `null` when there is no conflict.", + "example": "review_required", + "type": "string" + }, + "dry_run": { + "description": "`true` when the upgrade was computed without writing any changes; `false` when changes were committed.", + "example": true, + "type": "boolean" + }, + "existing_solution_version": { + "description": "Version string of the currently installed solution, as declared in its manifest. `null` if no prior version is installed.", + "example": "1.0.0", + "type": "string" + }, + "incoming_solution_version": { + "description": "Version string of the incoming solution to be installed, as declared in its manifest. `null` if the incoming manifest omits a version.", + "example": "1.0.0", + "type": "string" + }, + "message": { + "description": "Human-readable description of the conflict or error. `null` when there is no conflict.", + "example": "string", + "type": "string" + }, + "review_fingerprint": { + "description": "Opaque fingerprint that uniquely identifies this diff. Pass this value as `review_fingerprint` on a subsequent non-dry-run upgrade call to confirm you have reviewed the diff. `null` if not applicable.", + "example": "string", + "type": "string" + }, + "status": { + "description": "Overall result of the upgrade. `\"ready\"` means the upgrade can proceed; `\"conflict\"` means a blocking issue was detected and the upgrade was not applied.", + "example": "ready", + "type": "string" + }, + "summary": { + "$ref": "#/components/schemas/SolutionDiffSummary", + "description": "Aggregate counts of each action type across all diff entries." + }, + "version_change": { + "description": "Describes the nature of the version transition. One of `\"upgrade\"`, `\"downgrade\"`, `\"same\"`, or `\"unknown\"`.", + "example": "upgrade", + "type": "string" + } + }, + "required": [ + "status", + "dry_run", + "version_change", + "summary", + "changes" + ], + "type": "object" + }, + "StatusPing": { + "description": "Health check response confirming the API is reachable and indicating whether the caller's token is valid.", + "example": { + "deployment": { + "environment": "string", + "release": "string" + }, + "success": true, + "token": {}, + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + }, + "properties": { + "deployment": { + "$ref": "#/components/schemas/Deployment", + "description": "Deployment metadata." + }, + "success": { + "description": "`true` when the platform is reachable and the request was processed successfully.", + "example": true, + "type": "boolean" + }, + "token": { + "description": "Details about the authentication token used in this request.", + "example": {}, + "type": "object" + }, + "user": { + "$ref": "#/components/schemas/User", + "description": "The authenticated user associated with the token. `null` when the token is invalid or absent." + } + }, + "required": [ + "success", + "token" + ], + "type": "object" + }, + "StorageFile": { + "description": "A file stored in the platform's object storage, with metadata and a signed URL for downloading its contents.", + "example": { + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "filename": "document.pdf", + "id": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "share_url": "https://example.com", + "size": 1024, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "app": { + "description": "ID of the app this file belongs to (`app_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "content_type": { + "description": "MIME type of the file, e.g. `\"image/png\"` or `\"application/pdf\"`.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When the file was uploaded (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "filename": { + "description": "Original filename as provided at upload time.", + "example": "document.pdf", + "type": "string" + }, + "id": { + "description": "File ID (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "$ref": "#/components/schemas/ImageSource", + "description": "Image display metadata. Present only when `content_type` is an image type; `null` otherwise." + }, + "org": { + "description": "ID of the organization that owns this file (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox this file is scoped to (`sbx_...`). `null` for files not associated with a sandbox.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "share_url": { + "description": "Stable public URL for the file, fetchable without authentication. Present only when the file was shared (`share: true`); does not expire until sharing is disabled. Disabling and re-enabling sharing reactivates the same URL. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "size": { + "description": "Size of the file in bytes.", + "example": 1024, + "type": "integer" + }, + "team": { + "description": "ID of the team that owns this file (`team_...`). `null` if not team-owned.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the file record was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Short-lived signed URL for downloading the file. `null` if a URL could not be generated.", + "example": "https://example.com", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this file (`user_...`). `null` if not user-owned.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "SystemAccessToken": { + "description": "A long-lived API credential associated with a system account, used to authenticate server-to-server requests.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "expires_at": "2024-01-01T00:00:00Z", + "id": "sat_0aBcDeFgHiJkLmNoPqRsTu", + "last_used_at": "2024-01-01T00:00:00Z", + "name": "Example Name", + "revoked_at": "2024-01-01T00:00:00Z", + "scopes": "string", + "token": "string" + }, + "properties": { + "created_at": { + "description": "When this token was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "expires_at": { + "description": "When the token expires. `null` on legacy rows that predate stored expiry.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Token ID (`sat_...`).", + "example": "sat_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "last_used_at": { + "description": "When this token was last used to authenticate a request. `null` if the token has never been used.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "name": { + "description": "Human-readable label assigned to this token at creation time.", + "example": "Example Name", + "type": "string" + }, + "revoked_at": { + "description": "When this token was revoked. `null` if the token is still active.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "scopes": { + "description": "Space-separated OAuth scopes stamped on the token. `null` on legacy rows; treat as `full_access`.", + "example": "string", + "type": "string" + }, + "token": { + "description": "Raw bearer token string. Present only in the response to the create request; never returned again after that.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "Task": { + "description": "A task representing a unit of work, optionally assignable to a user or agent.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "blocked_by_count": { + "description": "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind.", + "example": 1, + "type": "integer" + }, + "closed_at": { + "description": "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "comments_count": { + "description": "Total number of comments posted on this task.", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the task was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by_actor": { + "$ref": "#/components/schemas/Actor", + "description": "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted)." + }, + "created_by_agent": { + "description": "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_by_user": { + "description": "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "current_lease": { + "allOf": [ + { + "$ref": "#/components/schemas/TaskSessionLeaseSummary" + } + ], + "description": "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "nullable": true + }, + "description": { + "description": "Long-form description or notes for the task. `null` if no description has been provided.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Task ID (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_blocked": { + "description": "`true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read.", + "example": true, + "type": "boolean" + }, + "links": { + "description": "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title of the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_actor": { + "$ref": "#/components/schemas/Actor", + "description": "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted)." + }, + "owner_agent": { + "description": "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_user": { + "description": "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level.", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "priority": { + "description": "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set.", + "example": 2, + "type": "integer" + }, + "sandbox": { + "description": "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`.", + "example": "open", + "type": "string" + }, + "subtasks_count": { + "description": "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.", + "example": 1, + "type": "integer" + }, + "tags": { + "description": "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the task was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status" + ], + "type": "object" + }, + "TaskComment": { + "description": "A comment posted on a task by a user or an agent, including resolved author information.", + "example": { + "author_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "author_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "author_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "body": "Please review the latest changes and let me know if anything looks off.", + "created_at": "2024-01-01T00:00:00Z", + "id": "tcm_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "task": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "author_actor": { + "$ref": "#/components/schemas/Actor", + "description": "Resolved author details including `id`, `name`, `alias`, and `profile_picture`. `null` if no author is set or the author cannot be resolved (e.g. authoring agent was deleted)." + }, + "author_agent": { + "description": "ID of the agent that posted this comment (`agi_...`). `null` if the author is a human user, or if the authoring agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "author_user": { + "description": "ID of the user who posted this comment (`usr_...`). `null` if the author is an agent, or if author provenance was cleared after the authoring agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "body": { + "description": "Plain-text body of the comment.", + "example": "Please review the latest changes and let me know if anything looks off.", + "type": "string" + }, + "created_at": { + "description": "When this comment was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Comment ID (`tcmt_...`).", + "example": "tcm_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org": { + "description": "ID of the organization that owns this comment (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Sandbox ID this comment is scoped to. `null` for comments outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "task": { + "description": "ID of the task this comment belongs to (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "team": { + "description": "ID of the team the task belongs to (`tem_...`). `null` if not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When this comment was last edited (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "body" + ], + "type": "object" + }, + "TaskSessionLease": { + "description": "A task-session lease returned only to its matching holder.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "lease_id": "string", + "renewed_at": "2024-01-01T00:00:00Z", + "session_id": "string", + "session_name": "Example Name" + }, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the matching coding session.", + "example": "string", + "type": "string" + }, + "lease_id": { + "description": "Caller-generated fencing token required for renewal and release.", + "example": "string", + "type": "string" + }, + "renewed_at": { + "description": "Server timestamp for the most recent claim, reclaim, or renewal.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "session_id": { + "description": "Opaque caller-generated coding-session identifier.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the matching coding session.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "lease_id", + "session_id", + "session_name", + "harness", + "expires_at", + "renewed_at" + ], + "type": "object" + }, + "TaskSessionLeaseSummary": { + "description": "Viewer-safe details about a task's current coding-session lease.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the coding session.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the coding session that holds the lease.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "session_name", + "harness", + "expires_at" + ], + "type": "object" + }, + "Team": { + "description": "A team within an organization, used to group users and agents and scope resources like configs, agents, and tasks.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "acl": { + "$ref": "#/components/schemas/Acl", + "description": "Access control list governing visibility and join permissions for this team. `null` when no ACL restrictions are applied and the team inherits default access rules." + }, + "app": { + "description": "ID of the developer application this team belongs to (`dap_...`). `null` if the team is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "badges": { + "description": "Aggregated badge counts for the team, keyed by category. `null` when badge data is not loaded.", + "example": {}, + "type": "object" + }, + "created_at": { + "description": "When this team was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Human-readable description of the team's purpose. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Team ID (`tem_...`).", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "membership_status": { + "description": "The authenticated viewer's role on this team. One of `\"owner\"`, `\"admin\"`, or `\"member\"`. `null` if the viewer is not a member.", + "example": "member", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this team. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Display name of the team.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this team belongs to (`org_...`). `null` if the team is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this team is scoped to (`dsb_...`). `null` outside sandbox contexts.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "slug": { + "description": "URL-safe slug for the team, derived from the team name. `null` if not set.", + "example": "example-slug", + "type": "string" + }, + "updated_at": { + "description": "When this team was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "TeamInvite": { + "description": "A team invite containing a short alphanumeric code that other users can present to join the team.", + "example": { + "code": "XKCD42" + }, + "properties": { + "code": { + "description": "Short alphanumeric join code. Pass this value as `join_code` to the join-with-code endpoint to add a user to the team.", + "example": "XKCD42", + "type": "string" + } + }, + "required": [ + "code" + ], + "type": "object" + }, + "TeamMembership": { + "description": "A record representing a user's or agent's membership in a team, including their resolved identity details and role.", + "example": { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "created_at": "2024-01-01T00:00:00Z", + "id": "tmb_0aBcDeFgHiJkLmNoPqRsTu", + "joined_at": "2024-01-01T00:00:00Z", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "role": "member", + "team": {}, + "type": "user", + "updated_at": "2024-01-01T00:00:00Z", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + }, + "properties": { + "agent": { + "$ref": "#/components/schemas/Agent", + "description": "The agent associated with this membership, as an expanded agent object. `null` when the member is a user, the type is unknown, or the association is not preloaded." + }, + "created_at": { + "description": "When this membership record was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Team membership ID (`tmb_...`).", + "example": "tmb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "joined_at": { + "description": "When the principal joined the team (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this membership record. `null` if no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Display name of the member, derived from the associated user or agent. `null` if the principal is unknown.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "$ref": "#/components/schemas/ImageSource", + "description": "Profile picture of the member, derived from the associated user or agent. `null` if not set or principal is unknown." + }, + "role": { + "description": "The member's role within the team. One of `\"owner\"`, `\"admin\"`, or `\"member\"`.", + "example": "member", + "type": "string" + }, + "team": { + "description": "The team this membership belongs to, as an expanded team object. `null` when the team association is not preloaded.", + "example": {}, + "type": "object" + }, + "type": { + "description": "Resolved principal type. One of `\"user\"`, `\"agent\"`, or `\"unknown\"` when the principal cannot be determined.", + "example": "user", + "type": "string" + }, + "updated_at": { + "description": "When this membership record was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "$ref": "#/components/schemas/User", + "description": "The user associated with this membership, as an expanded user object. `null` when the member is an agent, the type is unknown, or the association is not preloaded." + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "TeamMembershipListResponse": { + "description": "A paginated list of team memberships returned by the list team memberships endpoint.", + "example": { + "data": [ + { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "created_at": "2024-01-01T00:00:00Z", + "id": "tmb_0aBcDeFgHiJkLmNoPqRsTu", + "joined_at": "2024-01-01T00:00:00Z", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "role": "member", + "team": {}, + "type": "user", + "updated_at": "2024-01-01T00:00:00Z", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 20, + "total_entries": 1, + "total_pages": 1 + }, + "properties": { + "data": { + "description": "Array of team membership objects for the current page.", + "items": { + "$ref": "#/components/schemas/TeamMembership" + }, + "type": "array" + }, + "has_next": { + "description": "`true` if a subsequent page exists; `false` when this is the last page.", + "example": true, + "type": "boolean" + }, + "has_prev": { + "description": "`true` if a previous page exists; `false` when this is the first page.", + "example": true, + "type": "boolean" + }, + "page": { + "description": "Current page number, starting at `1`.", + "example": 1, + "type": "integer" + }, + "page_size": { + "description": "Maximum number of results returned per page.", + "example": 20, + "type": "integer" + }, + "total_entries": { + "description": "Total number of team memberships matching the applied filters across all pages.", + "example": 1, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages given the current `page_size`.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "Thread": { + "description": "A chat thread, representing a conversation channel that can be owned by a user, team, or agent and may contain messages, participants, and AI agent activity.", + "example": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + }, + "properties": { + "agent_user": { + "description": "ID of the agent that owns this thread (`agt_...`). `null` for user-owned or team-owned threads.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the thread was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "creator": { + "description": "User who created this thread. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if the creator is unknown.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "oneOf": [ + { + "type": "string" + }, + { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + }, + "description": { + "description": "Optional description or purpose statement for the thread. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Thread ID (`thr_...`).", + "example": "string", + "type": "string" + }, + "is_channel": { + "description": "Whether this thread operates as a channel — a multi-member broadcast-style conversation.", + "example": true, + "type": "boolean" + }, + "is_default": { + "description": "Whether this is the default thread for its owner. Each user or team has at most one default thread.", + "example": true, + "type": "boolean" + }, + "is_transient": { + "description": "Whether this thread is ephemeral and may be deleted automatically after a period of inactivity or when its TTL expires.", + "example": true, + "type": "boolean" + }, + "is_unlisted": { + "description": "Whether this thread is hidden from public discovery. Unlisted threads are accessible only to direct participants.", + "example": true, + "type": "boolean" + }, + "key": { + "description": "Application-defined stable key that uniquely identifies the thread within its scope. Useful for idempotent creation. `null` if not set.", + "example": "string", + "type": "string" + }, + "kind": { + "description": "Thread subtype: `\"standard\"` for ordinary threads, `\"slack_mirror\"` for the membership-strict mirror of a Slack channel, `\"slashwork_mirror\"` for the membership-strict mirror of a Slashwork group. Read-only — derived server-side at creation, never accepted from params.", + "example": "string", + "type": "string" + }, + "last_activity": { + "description": "When the most recent message was posted in this thread, falling back to the thread's creation time if it has no messages. Always populated on thread list endpoints (which order by it, after default threads); `null` on endpoints that don't compute activity enrichment.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "last_message_preview": { + "description": "Single-line snippet of the most recent message's text content (first non-empty line, truncated to 140 characters). Populated on thread list endpoints alongside `last_activity`; `null` when the thread has no messages, the latest message has no text content (e.g. attachment-only), or the endpoint doesn't compute activity enrichment.", + "example": "Sounds good — I'll ship the fix tomorrow.", + "type": "string" + }, + "last_message_sender": { + "description": "Display name of the sender of the most recent message — the same message `last_message_preview` snippets. Populated on thread list endpoints; `null` when the thread has no messages or the endpoint doesn't compute activity enrichment.", + "example": "Alice Chen", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the thread. Shape is application-defined; `null` if no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "muted": { + "description": "Whether the authenticated user has muted notifications for this thread. `true` suppresses all notification delivery.", + "example": true, + "type": "boolean" + }, + "org": { + "description": "ID of the organization this thread belongs to (`org_...`). `null` for threads outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent_message": { + "$ref": "#/components/schemas/Message", + "description": "The message that spawned this thread as a sub-thread. `null` for top-level threads." + }, + "participant": { + "description": "Array of participant user IDs (`usr_...`) who are members of this thread.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "participants": { + "description": "Expanded participant user objects for each member of this thread. Populated only when the association is loaded.", + "items": { + "$ref": "#/components/schemas/User" + }, + "type": "array" + }, + "participating_actor": { + "description": "Composite actor identifiers for all participants currently active in this thread. Present only when actor enrichment is requested.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "participating_agents": { + "description": "Expanded agent objects for all agents participating in this thread. Present only when agent enrichment is requested.", + "items": { + "$ref": "#/components/schemas/Agent" + }, + "type": "array" + }, + "role": { + "description": "The authenticated user's membership role in this thread, e.g. `\"owner\"`, `\"member\"`, or `\"viewer\"`. `null` if the user is not a member.", + "example": "member", + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this thread is scoped to (`dsb_...`). `null` for production threads.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "settings": { + "$ref": "#/components/schemas/ThreadSettings", + "description": "Per-thread configuration settings controlling AI agent behavior for this thread." + }, + "slug": { + "description": "URL-safe slug for the thread, used in human-readable permalinks. `null` if not assigned.", + "example": "example-slug", + "type": "string" + }, + "sub_threads": { + "description": "Threads that are nested under this thread as replies to a parent message. Present only when sub-thread enrichment is requested.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "tags": { + "description": "Status tags on the thread (e.g. `\"blocked\"`, `\"needs-review\"`). Edited by any thread participant via the `/threads/:thread/tags` endpoints and filterable on the thread list endpoints. Empty array if none set.", + "example": [ + "blocked", + "needs-review" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this thread (`team_...`). `null` for user-owned or agent-owned threads.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "title": { + "description": "Human-readable name of the thread. `null` if no title has been set.", + "example": "Example Title", + "type": "string" + }, + "ttl": { + "description": "Time-to-live in seconds after which the thread may be automatically cleaned up. `null` if the thread does not expire.", + "example": 3600, + "type": "integer" + }, + "unread_count": { + "description": "Number of messages in this thread that the authenticated user has not yet read. Present only when read-state enrichment is requested.", + "example": 5, + "type": "integer" + }, + "updated_at": { + "description": "When the thread was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user who owns this thread (`usr_...`). `null` for team-owned or agent-owned threads.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "visibility": { + "description": "Who can read the thread: `team` for every owning-team member, `restricted` for team-readable threads with an explicit roster, or `private` for roster-only access.", + "enum": [ + "team", + "restricted", + "private" + ], + "example": "team", + "type": "string" + } + }, + "required": [ + "id", + "visibility" + ], + "type": "object" + }, + "ThreadMessage": { + "description": "A single message posted to a thread, as seen from the developer portal. Includes sender information, optional attachments, and scoping identifiers.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "admin": {}, + "agent": "string", + "agent_mode": "cli", + "app": "string", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "content": "Hello! How can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "id": "string", + "metadata": { + "key": "value" + }, + "org": "string", + "root_message_id": "string", + "sandbox": "string", + "sender": "string", + "sender_name": "Example Name", + "sender_type": "user", + "team": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "$ref": "#/components/schemas/Acl", + "description": "Access control list for private messages. Only returned to resource owners (and privileged/org-admin viewers); `null` otherwise." + }, + "admin": { + "description": "Admin-only diagnostic metadata for the message, including execution trajectory details. Only present in developer portal responses.", + "example": {}, + "type": "object" + }, + "agent": { + "description": "Agent ID (`agt_...`) associated with the message. `null` if not agent-scoped.", + "example": "string", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "app": { + "description": "App ID (`app_...`) that the message belongs to.", + "example": "string", + "type": "string" + }, + "attachments": { + "description": "Files or media attached to the message. Empty array if no attachments are present.", + "items": { + "$ref": "#/components/schemas/Attachment" + }, + "type": "array" + }, + "content": { + "description": "Text content of the message. `null` if the message contains only attachments.", + "example": "Hello! How can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted to the thread (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Key-value metadata attached to the message. Always present; defaults to an empty object. The `metadata` query parameter filters on this same object, so a caller can read back the field it selects on.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "Organization ID (`org_...`) this message is scoped to. `null` if not org-scoped.", + "example": "string", + "type": "string" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "Sandbox ID (`dsb_...`) this message is scoped to. `null` if not sandbox-scoped.", + "example": "string", + "type": "string" + }, + "sender": { + "description": "Public ID of the sender (e.g. `usr_...` or `agt_...`). `null` for system-generated messages.", + "example": "string", + "type": "string" + }, + "sender_name": { + "description": "Display name of the message sender. `null` if unavailable.", + "example": "Example Name", + "type": "string" + }, + "sender_type": { + "description": "Category of entity that sent the message. One of `\"user\"`, `\"agent\"`, or `\"system\"`.", + "example": "user", + "type": "string" + }, + "team": { + "description": "Team ID (`tea_...`) associated with the message. `null` if not team-scoped.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) associated with the message. `null` if not user-scoped.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` follows thread membership; `private` is limited to the sender and ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "ThreadReadStatus": { + "description": "The read status of a thread for a specific user, indicating how far they have read and how many messages remain unread.", + "example": { + "last_read_message": "string", + "thread": "string", + "unread_count": 1 + }, + "properties": { + "last_read_message": { + "description": "Message ID (`msg_...`) of the last message the user has read in this thread. `null` if the user has never read any message in the thread.", + "example": "string", + "type": "string" + }, + "thread": { + "description": "Thread ID (`thr_...`) that this read status belongs to.", + "example": "string", + "type": "string" + }, + "unread_count": { + "description": "Number of messages in the thread that the user has not yet read.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "thread", + "unread_count" + ], + "type": "object" + }, + "ThreadSettings": { + "description": "Configuration settings for a thread that control AI agent behavior and other thread-level preferences.", + "example": { + "agent_enabled": true + }, + "properties": { + "agent_enabled": { + "description": "Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured.", + "example": true, + "type": "boolean" + } + }, + "type": "object" + }, + "Trajectory": { + "description": "A recorded sequence of AI messages and tool interactions representing a single AI reasoning session. Trajectories are stored as structured message logs and can be replayed or inspected after execution.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "id": "trj_0aBcDeFgHiJkLmNoPqRsTu", + "messages": {}, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "created_at": { + "description": "When the trajectory was recorded (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the storage file that persists the raw trajectory data (`fil_...`). `null` if the trajectory has not been written to a file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "id": { + "description": "Trajectory ID (`trj_...`).", + "example": "trj_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "messages": { + "description": "Serialized message log for this trajectory. Contains the ordered sequence of AI and tool messages produced during the session.", + "example": {}, + "type": "object" + }, + "org": { + "description": "ID of the organization this trajectory belongs to (`org_...`). `null` for trajectories outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this trajectory is scoped to (`sbx_...`). `null` for production trajectories.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "team": { + "description": "ID of the team this trajectory is scoped to (`team_...`). `null` for trajectories not associated with a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the trajectory record was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "UpgradeTemplateSummary": { + "description": "Compact summary of an AgentTemplate config referenced by an agent upgrade or source-solution response.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + }, + "User": { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "UserInvite": { + "description": "A shareable invite created by a user, optionally scoped to a thread. Recipients can use the invite key to join or start a conversation.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "id": "uin_0aBcDeFgHiJkLmNoPqRsTu", + "key": "string", + "metadata": { + "key": "value" + }, + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "user": { + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + }, + "properties": { + "created_at": { + "description": "When this invite was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Invite ID (`uin_...`).", + "example": "uin_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "key": { + "description": "Secret bearer token used to accept this invite. Treat this value like a password — do not log or expose it publicly.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the invite at creation time. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "thread": { + "description": "ID of the thread this invite is scoped to (`thr_...`). `null` if the invite is not bound to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "user": { + "$ref": "#/components/schemas/InviteCreator", + "description": "The user who created this invite." + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "ValidationResult": { + "description": "The result of a configuration validation check, indicating whether the config is valid and listing any errors or warnings.", + "example": { + "errors": [ + "Field 'name' is required" + ], + "valid": true, + "warnings": [ + "string" + ] + }, + "properties": { + "errors": { + "description": "List of human-readable error messages describing why validation failed. Empty or absent when `valid` is `true`.", + "example": [ + "Field 'name' is required" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "valid": { + "description": "`true` if the configuration passed all validation checks, `false` if one or more errors were found.", + "example": true, + "type": "boolean" + }, + "warnings": { + "description": "List of human-readable warning messages emitted during validation. Warnings do not cause `valid` to be `false` but indicate potentially problematic configuration.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "valid" + ], + "type": "object" + }, + "WorkerStatus": { + "description": "Execution state of the background worker processing a routine run. Reflects the current job status and retry progress.", + "example": { + "attempt": 1, + "max_attempts": 3, + "status": "executing" + }, + "properties": { + "attempt": { + "description": "Number of times the worker has been attempted so far. `0` means the job has been enqueued but not yet started.", + "example": 1, + "type": "integer" + }, + "max_attempts": { + "description": "Maximum number of attempts the worker is allowed before the job is marked `\"discarded\"`.", + "example": 3, + "type": "integer" + }, + "status": { + "description": "Current execution state of the worker. One of `\"queued\"`, `\"executing\"`, `\"retrying\"`, `\"completed\"`, `\"discarded\"`, or `\"cancelled\"`.", + "example": "executing", + "type": "string" + } + }, + "required": [ + "status", + "attempt", + "max_attempts" + ], + "type": "object" + }, + "WorkflowJournal": { + "description": "Summary of the durable workflow execution journal associated with a run.", + "example": { + "completed_at": "2024-01-01T00:00:00Z", + "created_at": "2024-01-01T00:00:00Z", + "current_sequence": 1, + "id": "wde_0aBcDeFgHiJkLmNoPqRsTu", + "started_at": "2024-01-01T00:00:00Z", + "status": "string", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "completed_at": { + "description": "When durable workflow execution reached a terminal state. `null` while it is active.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_at": { + "description": "When the journal was created.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "current_sequence": { + "description": "Highest workflow record sequence durably committed to this journal.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Journal execution ID (`wde_...`).", + "example": "wde_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "started_at": { + "description": "When durable workflow execution started.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "status": { + "description": "Current durable execution status: `pending`, `running`, `waiting`, `completed`, `failed`, or `cancelled`.", + "example": "string", + "type": "string" + }, + "updated_at": { + "description": "When the journal was last updated.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "status", + "current_sequence" + ], + "type": "object" + }, + "WorkflowJournalEntry": { + "description": "One ordered, replayable record from a durable workflow journal.", + "example": { + "command_id": "string", + "created_at": "2024-01-01T00:00:00Z", + "id": "wdr_0aBcDeFgHiJkLmNoPqRsTu", + "node_id": "string", + "record": {}, + "sequence": 1, + "timer_id": "string", + "type": "string" + }, + "properties": { + "command_id": { + "description": "Durable command identifier associated with the record, when present.", + "example": "string", + "type": "string" + }, + "created_at": { + "description": "When this entry was durably committed.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Journal entry ID (`wdr_...`).", + "example": "wdr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "node_id": { + "description": "Workflow node associated with the record. `null` for execution-level records.", + "example": "string", + "type": "string" + }, + "record": { + "description": "Replayable workflow record body, including payload, context, environment, metadata, and timestamp.", + "example": {}, + "type": "object" + }, + "sequence": { + "description": "Monotonically increasing sequence within the journal.", + "example": 1, + "type": "integer" + }, + "timer_id": { + "description": "Durable timer identifier associated with the record, when present.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Workflow record type, such as `node_started`, `node_completed`, or `node_failed`.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "sequence", + "type", + "record" + ], + "type": "object" + }, + "WorkflowWorkItem": { + "description": "Externally executable work yielded by a durable workflow.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "attempt_count": 1, + "command_id": "string", + "created_at": "2024-01-01T00:00:00Z", + "execution": "wde_0aBcDeFgHiJkLmNoPqRsTu", + "id": "wdi_0aBcDeFgHiJkLmNoPqRsTu", + "lease_expires_at": "2024-01-01T00:00:00Z", + "node_id": "string", + "payload": {}, + "routine_run": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "status": "string", + "type": "workflow_work_item", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "agent": { + "description": "Agent assigned to execute this work.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "attempt_count": { + "description": "Number of times this work has been freshly claimed or reclaimed.", + "example": 1, + "type": "integer" + }, + "command_id": { + "description": "Opaque journal command identity used to resume the workflow exactly once.", + "example": "string", + "type": "string" + }, + "created_at": { + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "execution": { + "description": "Durable workflow execution that owns this work.", + "example": "wde_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "id": { + "description": "Work item ID (`wdi_...`).", + "example": "wdi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lease_expires_at": { + "description": "When the current claim expires. Null for queued or terminal work.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "node_id": { + "description": "Workflow graph node that yielded the work.", + "example": "string", + "type": "string" + }, + "payload": { + "description": "Instructions and participant bindings needed to execute the work.", + "example": {}, + "type": "object" + }, + "routine_run": { + "description": "Routine run that owns the execution, when this work came from a routine.", + "example": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current queue lifecycle status.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Stable resource discriminator. Always `workflow_work_item`.", + "example": "workflow_work_item", + "type": "string" + }, + "updated_at": { + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "type", + "id", + "status", + "agent", + "execution", + "command_id", + "node_id", + "payload", + "attempt_count", + "created_at", + "updated_at" + ], + "type": "object" + }, + "WorkflowWorkItemClaim": { + "description": "Result of polling an agent's durable workflow work queue.", + "example": { + "data": { + "lease_owner": "string", + "work_item": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "attempt_count": 1, + "command_id": "string", + "created_at": "2024-01-01T00:00:00Z", + "execution": "wde_0aBcDeFgHiJkLmNoPqRsTu", + "id": "wdi_0aBcDeFgHiJkLmNoPqRsTu", + "lease_expires_at": "2024-01-01T00:00:00Z", + "node_id": "string", + "payload": {}, + "routine_run": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "status": "string", + "type": "workflow_work_item", + "updated_at": "2024-01-01T00:00:00Z" + } + } + }, + "properties": { + "data": { + "$ref": "#/components/schemas/WorkflowWorkItemLease", + "description": "Claimed or resumed work and its lease; null when no eligible item exists." + } + }, + "type": "object" + }, + "WorkflowWorkItemLease": { + "description": "A claimed workflow work item and its caller-held lease token.", + "example": { + "lease_owner": "string", + "work_item": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "attempt_count": 1, + "command_id": "string", + "created_at": "2024-01-01T00:00:00Z", + "execution": "wde_0aBcDeFgHiJkLmNoPqRsTu", + "id": "wdi_0aBcDeFgHiJkLmNoPqRsTu", + "lease_expires_at": "2024-01-01T00:00:00Z", + "node_id": "string", + "payload": {}, + "routine_run": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "status": "string", + "type": "workflow_work_item", + "updated_at": "2024-01-01T00:00:00Z" + } + }, + "properties": { + "lease_owner": { + "description": "Opaque lease token that must be persisted and presented for later transitions.", + "example": "string", + "type": "string" + }, + "work_item": { + "$ref": "#/components/schemas/WorkflowWorkItem", + "description": "The claimed, resumed, started, or heartbeated work item." + } + }, + "required": [ + "work_item", + "lease_owner" + ], + "type": "object" + }, + "WorkflowWorkItemList": { + "description": "Active durable workflow work available to the viewer.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "attempt_count": 1, + "command_id": "string", + "created_at": "2024-01-01T00:00:00Z", + "execution": "wde_0aBcDeFgHiJkLmNoPqRsTu", + "id": "wdi_0aBcDeFgHiJkLmNoPqRsTu", + "lease_expires_at": "2024-01-01T00:00:00Z", + "node_id": "string", + "payload": {}, + "routine_run": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "status": "string", + "type": "workflow_work_item", + "updated_at": "2024-01-01T00:00:00Z" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor for the next page, or null at the end.", + "example": "string", + "type": "string" + }, + "before_cursor": { + "description": "Always null because queue pagination is forward-only.", + "example": "string", + "type": "string" + }, + "data": { + "description": "Active work items. Lease tokens are intentionally never included in list responses.", + "items": { + "$ref": "#/components/schemas/WorkflowWorkItem" + }, + "type": "array" + }, + "has_more": { + "description": "Whether another page of work exists.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + }, + "WorkingMemoryEntry": { + "description": "A key-value memory record stored for an agent, optionally scoped to a user. Memory entries persist across invocations and may carry an expiration time.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "expires_at": "2024-01-01T00:00:00Z", + "id": "amm_0aBcDeFgHiJkLmNoPqRsTu", + "key": "user_preference", + "updated_at": "2024-01-01T00:00:00Z", + "value": "string" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this memory entry (`agt_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When this memory entry was first written (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "expires_at": { + "description": "When this entry will be automatically deleted. `null` if the entry does not expire.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Working memory entry ID (`amm_...`).", + "example": "amm_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "key": { + "description": "The string key used to look up this memory entry within the agent's memory namespace.", + "example": "user_preference", + "type": "string" + }, + "updated_at": { + "description": "When this memory entry was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "value": { + "description": "The string value stored under `key`. May be any serialized content the agent wrote.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "WorkingMemoryEntryListResponse": { + "description": "Paginated list of working memory entries stored for an agent. Includes page metadata to support sequential page traversal.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "expires_at": "2024-01-01T00:00:00Z", + "id": "amm_0aBcDeFgHiJkLmNoPqRsTu", + "key": "user_preference", + "updated_at": "2024-01-01T00:00:00Z", + "value": "string" + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 20, + "total_entries": 1, + "total_pages": 1 + }, + "properties": { + "data": { + "description": "Array of working memory entry objects for the current page.", + "items": { + "$ref": "#/components/schemas/WorkingMemoryEntry" + }, + "type": "array" + }, + "has_next": { + "description": "`true` if a subsequent page exists and can be fetched by incrementing the page number.", + "example": true, + "type": "boolean" + }, + "has_prev": { + "description": "`true` if a previous page exists and can be fetched by decrementing the page number.", + "example": true, + "type": "boolean" + }, + "page": { + "description": "The current page number, starting at `1`.", + "example": 1, + "type": "integer" + }, + "page_size": { + "description": "Maximum number of entries returned per page.", + "example": 20, + "type": "integer" + }, + "total_entries": { + "description": "Total number of working memory entries matching the query across all pages.", + "example": 1, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages given the current `page_size`.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "info": { + "description": "Agent-first API for runtime + developer control-plane operations (users, teams, agents, routines, context, workflows, integrations, and webhooks).", + "title": "ArchAstro Platform API", + "version": "v1" + }, + "openapi": "3.0.0", + "paths": { + "/api/v1/activity_feed": { + "get": { + "description": "Returns a cursor-paginated list of activity feed entries visible to the\nauthenticated user. Entries are ordered from newest to oldest by default.\nUse `before_cursor` to page backward and `after_cursor` to page forward.\n\nResults are scoped to the caller's app. All filter params are optional and\ncan be combined. Passing multiple values in an array filter returns entries\nmatching any of the supplied values (OR semantics).\n\nInvalid `kind` or `level` values return a 400 error listing the accepted\nvalues rather than being silently ignored.\n", + "operationId": "get_api_v1_activity_feed", + "parameters": [ + { + "description": "One or more entry kinds to include. Accepted values: routine_run, automation_run, thread_story, agent_quality_verdict, work_item_assigned, work_item_completed, generic. Omit to return all kinds.", + "example": [ + "string" + ], + "in": "query", + "name": "kind", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "One or more severity levels to include. Accepted values: debug, info, warn, error, audit. Omit to return all levels.", + "example": [ + "string" + ], + "in": "query", + "name": "level", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Restrict results to entries associated with these agent IDs (`agt_...`). Accepts multiple values.", + "example": [ + "string" + ], + "in": "query", + "name": "agent", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Restrict results to entries associated with these thread IDs (`thr_...`). Accepts multiple values.", + "example": [ + "string" + ], + "in": "query", + "name": "thread", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Restrict results to entries associated with these team IDs (`tem_...`). Accepts multiple values.", + "example": [ + "string" + ], + "in": "query", + "name": "team", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Restrict results to entries associated with these organization IDs (`org_...`). Accepts multiple values.", + "example": [ + "string" + ], + "in": "query", + "name": "org", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Restrict results to entries that share this correlation group identifier. Useful for tracing a chain of related events.", + "example": "string", + "in": "query", + "name": "correlation_id", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of entries to return per page. Defaults to 50; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor from a previous response's `before_cursor` field. Returns entries older than the cursor's position.", + "example": "string", + "in": "query", + "name": "before_cursor", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Opaque cursor from a previous response's `after_cursor` field. Returns entries newer than the cursor's position.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Cursor-paginated list of activity feed entries.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "attachments": [ + {} + ], + "automation_run": "atr_0aBcDeFgHiJkLmNoPqRsTu", + "content": "The agent completed the task successfully.", + "correlation_id": "01234567-89ab-cdef-0123-456789abcdef", + "created_at": "2024-01-01T00:00:00Z", + "id": "afe_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_step", + "level": "info", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "routine_run": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "session_record": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor to pass as `after_cursor` to retrieve the next newer page. Absent when no newer entries exist.", + "example": "string", + "type": "string" + }, + "before_cursor": { + "description": "Opaque cursor to pass as `before_cursor` to retrieve the next older page. Absent when no older entries exist.", + "example": "string", + "type": "string" + }, + "data": { + "description": "Array of activity feed entry objects for the current page, ordered newest first.", + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "attachments": [ + {} + ], + "automation_run": "atr_0aBcDeFgHiJkLmNoPqRsTu", + "content": "The agent completed the task successfully.", + "correlation_id": "01234567-89ab-cdef-0123-456789abcdef", + "created_at": "2024-01-01T00:00:00Z", + "id": "afe_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_step", + "level": "info", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "routine_run": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "session_record": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A single event record in an activity feed, capturing what happened, who caused it, and which resources were involved.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "attachments": [ + {} + ], + "automation_run": "atr_0aBcDeFgHiJkLmNoPqRsTu", + "content": "The agent completed the task successfully.", + "correlation_id": "01234567-89ab-cdef-0123-456789abcdef", + "created_at": "2024-01-01T00:00:00Z", + "id": "afe_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_step", + "level": "info", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "routine_run": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "session_record": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "The agent that produced this event. Returns an agent ID (`agi_...`) by default, or an expanded agent object when the association is loaded. `null` if no agent is associated.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "oneOf": [ + { + "type": "string" + }, + { + "description": "An AI agent that can be configured with tools, routines, and skills, and invoked to handle conversations or tasks.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints.", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "solution": { + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + }, + "app": { + "description": "ID of the application that produced this entry (`dap_...`). `null` if not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "attachments": { + "description": "Array of attachment objects associated with this entry. Each attachment has a `type` field (e.g. `\"file\"`, `\"task\"`, `\"artifact\"`) and type-specific additional fields. Empty array when there are no attachments.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "automation_run": { + "description": "ID of the automation run that produced this entry (`atr_...`). `null` if not produced by an automation run.", + "example": "atr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "content": { + "description": "A longer explanation of the event rendered as Markdown. `null` if no additional content is available.", + "example": "The agent completed the task successfully.", + "type": "string" + }, + "correlation_id": { + "description": "An opaque string used to group related entries together. Entries sharing the same `correlation_id` belong to a single logical operation. `null` if not correlated.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "created_at": { + "description": "When this activity feed entry was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Activity feed entry ID (`afe_...`).", + "example": "afe_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "The type of event this entry represents, e.g. `\"agent_step\"` or `\"tool_call\"`. Determines how `title`, `content`, and `attachments` should be interpreted.", + "example": "agent_step", + "type": "string" + }, + "level": { + "description": "Severity level of the event. One of `\"info\"`, `\"warning\"`, or `\"error\"`. `null` if no severity is set.", + "example": "info", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata stored on this entry. Returns an empty object when no metadata is set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization this entry belongs to (`org_...`). `null` if not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "routine_run": { + "description": "ID of the agent routine run that produced this entry (`arr_...`). `null` if not produced by a routine run.", + "example": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Identifier of the sandbox environment this entry was generated in. `null` in production contexts.", + "example": "string", + "type": "string" + }, + "session_record": { + "description": "ID of the agent session record this entry belongs to (`ase_...`). `null` if not part of an agent session.", + "example": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "team": { + "description": "ID of the team this entry is associated with (`tem_...`). `null` if not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this entry is associated with (`thr_...`). `null` if not linked to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "title": { + "description": "A one-line human-readable summary of the event. `null` if the entry has no title.", + "example": "Example Title", + "type": "string" + }, + "updated_at": { + "description": "When this activity feed entry was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "The user who triggered this event. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if no user is associated.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "oneOf": [ + { + "type": "string" + }, + { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "description": "`true` when additional entries exist beyond this page in the requested direction.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Invalid cursor" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + } + }, + "summary": "List activity feed entries", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_computers/{computer}": { + "delete": { + "description": "Permanently deletes the specified computer and releases all associated\ninfrastructure resources. This action is irreversible — once deleted,\nthe computer cannot be recovered and its ID becomes invalid.\n\nRequires an app-scoped API key. The computer must belong to the same app.\nReturns `204 No Content` on success.\n", + "operationId": "delete_api_v1_agent_computers__computer", + "parameters": [ + { + "description": "Computer ID (`cmp_...`). The computer to delete.", + "example": "string", + "in": "path", + "name": "computer", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response body. Returns HTTP 204 on success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Computer not found" + } + }, + "summary": "Delete a computer", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the computer identified by `computer`. The computer must belong to the\napp associated with the API key.\n\nUse this endpoint to inspect a computer's current `status`, `region`,\n`config`, and `metadata` after provisioning or to verify its state before\nissuing commands. For a live status update, use the refresh endpoint instead.\n", + "operationId": "get_api_v1_agent_computers__computer", + "parameters": [ + { + "description": "Computer ID (`cmp_...`). The computer to retrieve.", + "example": "string", + "in": "path", + "name": "computer", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentComputer" + } + } + }, + "description": "The requested computer." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Computer not found" + } + }, + "summary": "Retrieve a computer", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_computers/{computer}/exec": { + "post": { + "description": "Runs a shell command on the specified computer and returns its combined\noutput and exit code. The call blocks until the command completes; there\nis no streaming or timeout override — plan accordingly for long-running\ncommands.\n\nRequires an app-scoped API key. The computer must be in the `running`\nstate. Commands run as the default unprivileged user on the computer.\nA non-zero `exit_code` in the response does not produce an HTTP error;\ninspect `exit_code` and `output` to determine success.\n", + "operationId": "post_api_v1_agent_computers__computer_exec", + "parameters": [ + { + "description": "Computer ID (`cmp_...`). The computer on which to run the command.", + "example": "string", + "in": "path", + "name": "computer", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "command": "string", + "dir": "string" + }, + "properties": { + "command": { + "description": "Shell command to execute, e.g. `\"ls -la /home\"`.", + "example": "string", + "type": "string" + }, + "dir": { + "description": "Absolute path to use as the working directory when executing the command. Defaults to the computer's home directory when omitted.", + "example": "string", + "type": "string" + } + }, + "required": [ + "command" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComputerExecResult" + } + } + }, + "description": "The output and exit code produced by the command." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Computer not found" + }, + "422": { + "description": "Execution failed" + } + }, + "summary": "Execute a command on a computer", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_computers/{computer}/refresh": { + "post": { + "description": "Fetches the latest status for the specified computer from the upstream\nprovisioning provider and updates the platform record accordingly. Use this\nendpoint to reconcile a computer whose `status` appears stale or stuck in\na transitional state such as `provisioning`.\n\nRequires an app-scoped API key. Returns 422 if the computer has not been\nfully provisioned yet. The updated computer object is returned on success.\n", + "operationId": "post_api_v1_agent_computers__computer_refresh", + "parameters": [ + { + "description": "Computer ID (`cmp_...`). The computer whose status should be refreshed.", + "example": "string", + "in": "path", + "name": "computer", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentComputer" + } + } + }, + "description": "The computer record with its status updated from the provisioning provider." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Computer not found" + } + }, + "summary": "Refresh a computer's status", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_env_vars/{env_var}": { + "delete": { + "description": "Permanently deletes the specified environment variable from the agent. This\naction is irreversible; the stored value is destroyed and cannot be recovered.\n\nThe authenticated user must have access to the agent's parent app. Pass the\napp scope via the `app` parameter when calling with an API key that is scoped\nto a specific app. Returns `204 No Content` on success.\n", + "operationId": "delete_api_v1_agent_env_vars__env_var", + "parameters": [ + { + "description": "Environment variable ID (`anv_...`) of the variable to delete.", + "example": "string", + "in": "path", + "name": "env_var", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response. Returns HTTP 204 No Content on successful deletion." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Not found" + } + }, + "summary": "Delete an agent environment variable", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the environment variable identified by `env_var`. The stored value\nis always masked in the response; only the last four characters are visible.\nThere is no endpoint that returns the plaintext value after creation.\n\nThe authenticated user must have access to the agent's parent app. Pass the\napp scope via the `app` parameter when calling with an API key that is scoped\nto a specific app.\n", + "operationId": "get_api_v1_agent_env_vars__env_var", + "parameters": [ + { + "description": "Environment variable ID (`anv_...`) to retrieve.", + "example": "string", + "in": "path", + "name": "env_var", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentEnvVarMasked" + } + } + }, + "description": "The requested environment variable with its value masked." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Not found" + } + }, + "summary": "Retrieve an agent environment variable", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "patch": { + "description": "Updates the `value` or `description` of an existing environment variable.\nOnly fields provided in the request are changed; omitted fields retain their\ncurrent values. The variable `key` cannot be changed after creation.\n\nThe updated value is stored securely and, like creation, the plaintext is\nnever returned; the response contains the masked representation. The\nauthenticated user must have access to the agent's parent app. Pass the app\nscope via the `app` parameter when calling with an API key that is scoped to\na specific app.\n", + "operationId": "patch_api_v1_agent_env_vars__env_var", + "parameters": [ + { + "description": "Environment variable ID (`anv_...`) to update.", + "example": "string", + "in": "path", + "name": "env_var", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "description": "An example description.", + "value": "string" + }, + "properties": { + "description": { + "description": "Updated human-readable note describing what the variable is used for.", + "example": "An example description.", + "type": "string" + }, + "value": { + "description": "New plaintext secret value. The value is encrypted at rest and never returned in full.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentEnvVarMasked" + } + } + }, + "description": "The updated environment variable with its value masked." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Update an agent environment variable", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_health_actions/{health_action}": { + "get": { + "description": "Returns a single agent health action by its ID. Use this endpoint to\nfetch the current state of a specific health action — for example, to\nrefresh a checklist item after the user completes a setup step or after\npolling for status changes.\n\nThe caller must be authenticated and scoped to the app that owns the\nhealth action. Returns 404 if the health action does not exist or is not\naccessible within the current app scope.\n", + "operationId": "get_api_v1_agent_health_actions__health_action", + "parameters": [ + { + "description": "Health action ID (`aha_...`) to retrieve.", + "example": "string", + "in": "path", + "name": "health_action", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentHealthAction" + } + } + }, + "description": "The requested health action object." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Agent health action not found" + } + }, + "summary": "Retrieve a health action", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_health_actions/{health_action}/verify": { + "post": { + "description": "Synchronously re-runs the verifier for the specified health action and\nreturns the updated health action object. Use this endpoint to power\noperator-facing \"Verify\" buttons that let users confirm a setup step is\ncomplete (for example, after setting an environment variable or\ncompleting an OAuth install).\n\nThe verifier transitions the action's `status` field according to the\nfollowing rules: a `pending` action that passes becomes `completed`; one\nthat fails stays `pending`. A `completed` action that passes stays\n`completed`; one that fails becomes `degraded`. A `degraded` action that\npasses returns to `completed`; one that fails stays `degraded`. Actions\nin `skipped` status are never transitioned — the call returns the\nunchanged record.\n\nThis endpoint runs the verifier synchronously and blocks until the check\nfinishes. For background or probe-driven verification sweeps, use the\nplatform's internal debounced trigger instead of calling this endpoint\nin a tight loop. Returns 422 if the verifier itself encounters an\nunrecoverable error.\n", + "operationId": "post_api_v1_agent_health_actions__health_action_verify", + "parameters": [ + { + "description": "Health action ID (`aha_...`) to verify.", + "example": "string", + "in": "path", + "name": "health_action", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentHealthAction" + } + } + }, + "description": "The health action object with its `status` and `last_verified_at` updated to reflect the result of the verification run." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Agent health action not found" + }, + "422": { + "description": "Verifier failed to run for this health action" + } + }, + "summary": "Verify a health action", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_installations": { + "get": { + "description": "Returns all installations across every agent in the authenticated app. Use this\nendpoint to get a global view of all external service and enablement channel\nconnections for the app.\n\nOptionally narrow results to a single agent by passing the `agent` parameter. To\nlist installations scoped to a specific agent, you may also use the per-agent List\nInstallations endpoint. Results are returned as an unordered array with no\npagination. The caller must have app scope.\n", + "operationId": "get_api_v1_agent_installations", + "parameters": [ + { + "description": "Agent IDs (`agi_...`) to filter results by. When omitted, installations for all agents in the app are returned. Multiple values are OR'd.", + "example": [ + "string" + ], + "in": "query", + "name": "agent", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstallationListResponse" + } + } + }, + "description": "The list of installations for the app, optionally filtered by agent." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + } + }, + "summary": "List installations for an app", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_installations/{installation}": { + "delete": { + "description": "Permanently deletes an installation and severs the connection between the agent\nand the external service or enablement channel. Any backing context sources\nassociated with the installation are also removed.\n\nThis action is irreversible. If you want to temporarily stop an installation from\nprocessing events, use the Pause or Suspend endpoints instead. The caller must have\napp scope for the app that owns the installation.\n", + "operationId": "delete_api_v1_agent_installations__installation", + "parameters": [ + { + "description": "Installation ID (`cin_...`) to delete.", + "example": "string", + "in": "path", + "name": "installation", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response with HTTP 204 status on successful deletion." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Installation not found" + } + }, + "summary": "Delete an installation", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns a single installation by ID. Use this endpoint to check the current\n`state`, `kind`, `config`, and bound integration of an installation.\n\nThe installation must belong to an agent that is accessible within the\nauthenticated app's scope. The caller must have app scope for the app that\nowns the installation.\n", + "operationId": "get_api_v1_agent_installations__installation", + "parameters": [ + { + "description": "Installation ID (`cin_...`) to retrieve.", + "example": "string", + "in": "path", + "name": "installation", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Installation" + } + } + }, + "description": "The requested installation." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Installation not found" + } + }, + "summary": "Retrieve an installation", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_installations/{installation}/activate": { + "post": { + "description": "Transitions an installation from a pending or paused state to `active`, enabling\nthe agent to receive events and process work through the installed integration or\nenablement channel.\n\nActivation requires that the installation already has a bound integration (either\nvia `shared_integration` or an inline `integration` created at install time). If no\nintegration is bound, the request returns 422. The caller must have app scope for\nthe app that owns the installation.\n", + "operationId": "post_api_v1_agent_installations__installation_activate", + "parameters": [ + { + "description": "Installation ID (`cin_...`) to activate.", + "example": "string", + "in": "path", + "name": "installation", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Installation" + } + } + }, + "description": "The updated installation with `state` reflecting the new active status." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Installation not found" + }, + "422": { + "description": "Cannot activate - requires integration or invalid state" + } + }, + "summary": "Activate an installation", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_installations/{installation}/installation_sources": { + "get": { + "description": "Returns all sources attached to the specified installation. Sources represent\nthe content units (documents, links, and other typed payloads) that the\ninstallation's agent can access as context.\n\nThis endpoint requires an app-scoped token. Results include sources in all\nstates, including those still being ingested. Inspect each source's `state`\nfield to determine whether its content is ready.\n", + "operationId": "get_api_v1_agent_installations__installation_installation_sources", + "parameters": [ + { + "description": "Installation ID (`cin_...`) whose sources to retrieve.", + "example": "string", + "in": "path", + "name": "installation", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstallationSourceListResponse" + } + } + }, + "description": "Object containing the list of sources attached to the installation." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Installation not found" + } + }, + "summary": "List sources for an installation", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Attaches a new source to an existing installation, making its content available\nto the installation's agent as context. The source type and payload must be valid\nfor the installation's kind; invalid combinations return 422.\n\nThis endpoint requires an app-scoped token. The installation must belong to an\nagent accessible by the authenticated caller. Once created, the source begins\nprocessing asynchronously — its `state` will transition from `\"pending\"` as\ningestion progresses.\n", + "operationId": "post_api_v1_agent_installations__installation_installation_sources", + "parameters": [ + { + "description": "Installation ID (`cin_...`) to attach the source to.", + "example": "string", + "in": "path", + "name": "installation", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "payload": {}, + "type": "string" + }, + "properties": { + "payload": { + "description": "Type-specific payload for the source. The accepted keys depend on the `type` value; invalid or missing payload fields return 422.", + "example": {}, + "type": "object" + }, + "type": { + "description": "Source type slug identifying the kind of content being attached, e.g. `\"file/document\"` or `\"web/link\"`.", + "example": "string", + "type": "string" + } + }, + "required": [ + "type", + "payload" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstallationSource" + } + } + }, + "description": "The newly created installation source." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Installation not found" + }, + "422": { + "description": "Invalid source type, state, or payload" + } + }, + "summary": "Add a source to an installation", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_installations/{installation}/pause": { + "post": { + "description": "Transitions an active installation to the `paused` state, temporarily stopping\nthe agent from receiving events through this installation. The installation and\nits integration binding are preserved and can be resumed by calling the Activate\nendpoint.\n\nOnly installations in the `active` state can be paused. Attempting to pause an\ninstallation in any other state returns 422. The caller must have app scope for\nthe app that owns the installation.\n", + "operationId": "post_api_v1_agent_installations__installation_pause", + "parameters": [ + { + "description": "Installation ID (`cin_...`) to pause.", + "example": "string", + "in": "path", + "name": "installation", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Installation" + } + } + }, + "description": "The updated installation with `state` set to `\"paused\"`." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Installation not found" + }, + "422": { + "description": "Cannot pause - invalid state" + } + }, + "summary": "Pause an installation", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_installations/{installation}/suspend": { + "post": { + "description": "Transitions an installation to the `suspended` state, disabling event processing\nand signaling that the installation requires administrative attention. Unlike\npausing, suspension typically indicates a policy or compliance hold rather than a\ntemporary operational stop.\n\nAn optional `reason` string can be supplied to record why the installation was\nsuspended; this is stored on the installation and visible when you retrieve it.\nOnly installations that are not already suspended can be suspended — sending this\nrequest for an already-suspended installation returns 422. The caller must have\napp scope for the app that owns the installation.\n", + "operationId": "post_api_v1_agent_installations__installation_suspend", + "parameters": [ + { + "description": "Installation ID (`cin_...`) to suspend.", + "example": "string", + "in": "path", + "name": "installation", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "reason": "string" + }, + "properties": { + "reason": { + "description": "Human-readable explanation for the suspension. Stored on the installation and visible when you retrieve it. Omit to suspend without recording a reason.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Installation" + } + } + }, + "description": "The updated installation with `state` set to `\"suspended\"`." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Installation not found" + }, + "422": { + "description": "Cannot suspend - already suspended or invalid state" + } + }, + "summary": "Suspend an installation", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_routine_runs": { + "get": { + "description": "Returns a paginated list of agent routine runs across all routines visible to\nthe authenticated app scope. Results are ordered by creation time descending\n(most recent first).\n\nUse the `agent` parameter to filter runs to one or more specific agents. Use\n`status` to narrow results to runs in a particular state. Pagination is\nbidirectional: supply `after_cursor` to page forward through newer runs or\n`before_cursor` to page backward through older runs.\n\nThis endpoint requires an app scope. Requests without a valid app credential\nreturn 403.\n", + "operationId": "get_api_v1_agent_routine_runs", + "parameters": [ + { + "description": "Filter by one or more agent IDs (`agi_...`) or `lookup_key` values. Repeat the parameter (e.g. `?agent[]=agi_a&agent[]=agi_b`) to OR multiple agents. Omit to return runs for all agents.", + "example": [ + "string" + ], + "in": "query", + "name": "agent", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Filter by run status. One of `\"pending\"`, `\"running\"`, `\"completed\"`, `\"failed\"`, `\"skipped\"`, or `\"cancelled\"`. Omit to return runs in any status.", + "example": "string", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of runs to return. Defaults to 50; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor from a previous response's `before_cursor` field. Returns the page of runs older than that cursor position.", + "example": "string", + "in": "query", + "name": "before_cursor", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Opaque cursor from a previous response's `after_cursor` field. Returns the page of runs newer than that cursor position.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRoutineRunListResponse" + } + } + }, + "description": "Paginated list of agent routine runs." + }, + "400": { + "description": "Invalid cursor" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + } + }, + "summary": "List agent routine runs", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_routine_runs/{agent_routine_run}/stream": { + "get": { + "description": "Opens a long-lived Server-Sent Events connection that emits a `run_update`\nevent whenever the routine run's status changes, replaying the current status\nimmediately on connect. The stream closes when the run reaches a terminal\nstatus (`completed`, `failed`, `skipped`, `cancelled`) or the maximum stream\nduration elapses (a terminal `error` event with `stream_timeout` is sent).\nKeepalive comments are emitted on an interval to hold the connection open.\n", + "operationId": "get_api_v1_agent_routine_runs__agent_routine_run_stream", + "parameters": [ + { + "description": "ID of the agent routine run to stream status updates for.", + "example": "string", + "in": "path", + "name": "agent_routine_run", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "text/event-stream": { + "schema": { + "$ref": "#/components/schemas/AgentRoutineRun" + } + } + }, + "description": "Server-Sent Events stream" + }, + "404": { + "description": "Agent routine run not found" + } + }, + "summary": "Stream agent routine run status", + "x-auth": [ + "publishable_key", + "bearer" + ], + "x-sdk-streaming": { + "events": { + "run_update": { + "$ref": "#/components/schemas/AgentRoutineRun" + } + }, + "type": "sse" + } + } + }, + "/api/v1/agent_routines": { + "get": { + "description": "Returns all routines within the authenticated app scope. Optionally filter by\nagent or event type. When `agent` is omitted, all routines accessible to the\ncaller are returned regardless of which agent they belong to.\n\nIf `agent` is provided but does not exist or is not accessible, the endpoint\nreturns 404 rather than an empty list. Results are not paginated; all matching\nroutines are returned in a single response. Requires app scope.\n", + "operationId": "get_api_v1_agent_routines", + "parameters": [ + { + "description": "Agent IDs (`agi_...`) to filter routines by. Omit to return routines across all agents. Multiple values are OR'd.", + "example": [ + "string" + ], + "in": "query", + "name": "agent", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Event type string to filter by (e.g. `\"agentroutine.invoked\"`). Omit to return routines for all event types.", + "example": "string", + "in": "query", + "name": "event_type", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRoutineListResponse" + } + } + }, + "description": "Object containing a `data` array of matching routines." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + } + }, + "summary": "List routines", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_routines/presets": { + "get": { + "description": "Returns all registered routine presets available to the authenticated app,\nincluding each preset's name, display metadata, and accepted configuration\nschema. Use this endpoint to discover which presets can be referenced when\ncreating or updating a routine with `handler_type: \"preset\"`.\n\nThe list reflects presets registered at server start time and does not change\nat runtime. Requires app scope.\n", + "operationId": "get_api_v1_agent_routines_presets", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/RoutinePreset" + }, + "type": "array" + } + } + }, + "description": "Array of available routine preset objects." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + } + }, + "summary": "List routine presets", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_routines/runs/{run}": { + "get": { + "description": "Returns a single routine run by its ID. The run includes status, payload,\nresult, duration, and any structured response produced by the routine's agent.\n\nThe authenticated principal must have access to the app that owns the run.\nWhen your API key is scoped to an app, the run must belong to that app or\na 403 is returned.\n", + "operationId": "get_api_v1_agent_routines_runs__run", + "parameters": [ + { + "description": "Routine run ID (`arr_...`) to retrieve.", + "example": "string", + "in": "path", + "name": "run", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRoutineRun" + } + } + }, + "description": "The requested routine run." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Routine run not found" + } + }, + "summary": "Retrieve a routine run", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_routines/runs/{run}/journal": { + "get": { + "description": "Returns the durable workflow journal entries for one agent routine run in\nascending sequence order. Script-backed, preset-backed, and legacy runs may\nhave no journal; those runs return `journal: null` and an empty `data` array\nwith HTTP 200.\n\nPagination is forward-only. Pass `after_cursor` from the previous response\nto retrieve the next page.\n", + "operationId": "get_api_v1_agent_routines_runs__run_journal", + "parameters": [ + { + "description": "Routine run ID (`arr_...`) whose journal to retrieve.", + "example": "string", + "in": "path", + "name": "run", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of entries to return. Defaults to 50; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor from the previous response's `after_cursor` field.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunJournalPage" + } + } + }, + "description": "Forward-paginated routine run journal entries." + }, + "400": { + "description": "Invalid cursor" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Agent routine run not found" + } + }, + "summary": "List a routine run journal", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_routines/{routine}": { + "delete": { + "description": "Permanently deletes the specified routine. This action is irreversible — the\nroutine and its configuration are removed immediately. Any in-flight event\nprocessing initiated by this routine before deletion may still complete.\n\nRequires app scope. Returns 204 No Content on success.\n", + "operationId": "delete_api_v1_agent_routines__routine", + "parameters": [ + { + "description": "Routine ID (`arn_...`) of the routine to delete.", + "example": "string", + "in": "path", + "name": "routine", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response on successful deletion (HTTP 204 No Content)." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Routine not found" + } + }, + "summary": "Delete a routine", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the full routine record for the given routine ID. Use this endpoint to\ninspect a routine's current configuration, handler type, event config, schedule,\nand lifecycle status.\n\nRequires app scope. Returns 404 if the routine does not exist or is not\naccessible to the caller.\n", + "operationId": "get_api_v1_agent_routines__routine", + "parameters": [ + { + "description": "Routine ID (`arn_...`) of the routine to retrieve.", + "example": "string", + "in": "path", + "name": "routine", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRoutine" + } + } + }, + "description": "The requested routine." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Routine not found" + } + }, + "summary": "Retrieve a routine", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "patch": { + "description": "Updates one or more fields of the specified routine. Only the fields you\ninclude are changed; omitted fields retain their current values. To change the\nexecution model, supply a new `handler_type` along with its required handler\nbody field (`config`, `script`, or `preset_name`).\n\nWhen `template` is supplied, the routine's configuration is re-resolved from\nthe template before applying any additional field overrides. The routine's\n`status`, `lookup_key`, and agent attachment are always preserved regardless\nof template content. Updating `steps` replaces the entire step list — send\nthe full desired list, not a partial diff. Requires app scope.\n", + "operationId": "patch_api_v1_agent_routines__routine", + "parameters": [ + { + "description": "Routine ID (`arn_...`) of the routine to update.", + "example": "string", + "in": "path", + "name": "routine", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "config": "string", + "description": "An example description.", + "event_config": {}, + "event_type": "string", + "handler_type": "string", + "lookup_key": "string", + "message_policy": { + "recipients": [ + "routine_owner", + "run_actor" + ], + "visibility": "private" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "preset_config": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "preset_name": "Example Name", + "schedule": "string", + "script": "string", + "steps": [ + { + "config": "string", + "handler_type": "preset", + "inputs": {}, + "name": "Example Name", + "on_error": "halt", + "output_key": "string", + "preset_config": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "preset_name": "Example Name", + "script": "string" + } + ], + "template": "string", + "trigger_context": "string", + "user": "string" + }, + "properties": { + "acl": { + "description": "Updated access control list. Replaces the existing ACL entirely.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "config": { + "description": "Workflow config ID (`cfg_...`). Used when `handler_type` is `\"workflow_graph\"`.", + "example": "string", + "type": "string" + }, + "description": { + "description": "New human-readable description of what this routine does.", + "example": "An example description.", + "type": "string" + }, + "event_config": { + "description": "Mapping of event types to trigger configuration. Each key is an event type string; each value is an object with a `\"filters\"` map and an optional `\"dedupe_key_path\"` (a JSON path used to deduplicate events, e.g. `\"$.thread.id\"`).", + "example": {}, + "type": "object" + }, + "event_type": { + "description": "Event type that triggers this routine. Deprecated — use `event_config` instead.", + "example": "string", + "type": "string" + }, + "handler_type": { + "description": "New execution model. One of `\"workflow_graph\"`, `\"script\"`, `\"preset\"`, or `\"chain\"`.", + "example": "string", + "type": "string" + }, + "lookup_key": { + "description": "New stable, unique key for deterministic lookup. Must be unique within the app.", + "example": "string", + "type": "string" + }, + "message_policy": { + "description": "Updated visibility and explicit recipient selection for emitted messages.", + "example": { + "recipients": [ + "routine_owner", + "run_actor" + ], + "visibility": "private" + }, + "properties": { + "recipients": { + "description": "Required and non-empty for private visibility. Sources are additive. Routine owner includes the agent owner and optional user co-owner.", + "example": [ + "routine_owner", + "run_actor" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "visibility": { + "description": "Message visibility. One of `default` or `private`.", + "example": "private", + "type": "string" + } + }, + "type": "object" + }, + "metadata": { + "description": "Updated arbitrary key-value metadata. Replaces the existing metadata entirely.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "New human-readable display name for the routine.", + "example": "Example Name", + "type": "string" + }, + "preset_config": { + "description": "Updated configuration passed to the preset at runtime.", + "example": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "properties": { + "instructions": { + "description": "Custom task or behavior instructions for the preset (max 10,000 chars).", + "example": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "type": "string" + }, + "llm": { + "description": "LLM invocation settings (e.g. a `model` override for this routine/step).", + "example": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "properties": { + "model": { + "description": "Provider-prefixed model identifier for this routine or step, e.g. `\"openrouter/anthropic/claude-sonnet-latest\"`. When omitted, the agent's default model is used.", + "example": "openrouter/anthropic/claude-sonnet-latest", + "type": "string" + } + }, + "type": "object" + }, + "session_mode": { + "description": "Session mode: `stateless` (default, new session per trigger) or `session` (find-or-create a persistent session scoped by `session_scope`).", + "example": "stateless", + "type": "string" + }, + "session_scope": { + "description": "When `session_mode` is `session`, controls session scoping: `per_user` (default), `per_key`, `per_org`, or `global`.", + "example": "per_user", + "type": "string" + }, + "structured_message_template_ids": { + "description": "IDs of structured message templates that constrain the agent's responses to predefined structured formats.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "preset_name": { + "description": "Name of the registered preset to use. Used when `handler_type` is `\"preset\"`.", + "example": "Example Name", + "type": "string" + }, + "schedule": { + "description": "New cron expression for time-triggered routines (e.g. `\"0 9 * * 1\"`). Must not be more frequent than once per hour.", + "example": "string", + "type": "string" + }, + "script": { + "description": "New inline script source. Used when `handler_type` is `\"script\"`.", + "example": "string", + "type": "string" + }, + "steps": { + "description": "Updated ordered list of steps for a chain handler. Required when `handler_type` is `\"chain\"`; must be omitted or empty otherwise. Replaces the entire existing step list — send the full desired list, not a partial diff.", + "example": [ + { + "config": "string", + "handler_type": "preset", + "inputs": {}, + "name": "Example Name", + "on_error": "halt", + "output_key": "string", + "preset_config": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "preset_name": "Example Name", + "script": "string" + } + ], + "items": { + "description": "A single execution step within a chain-routine, describing the handler to invoke and how to handle errors or pass data between steps.", + "example": { + "config": "string", + "handler_type": "preset", + "inputs": {}, + "name": "Example Name", + "on_error": "halt", + "output_key": "string", + "preset_config": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "preset_name": "Example Name", + "script": "string" + }, + "properties": { + "config": { + "description": "ID of a saved config to use as the handler body. Required when `handler_type` is `\"workflow_graph\"`; also accepted for `\"script\"` as an alternative to an inline `script` value.", + "example": "string", + "type": "string" + }, + "handler_type": { + "description": "Execution handler for this step. One of `\"preset\"`, `\"script\"`, or `\"workflow_graph\"`.", + "example": "preset", + "type": "string" + }, + "inputs": { + "description": "Optional key-value map binding outputs from prior steps to this step's input variables.", + "example": {}, + "type": "object" + }, + "name": { + "description": "Optional label for this step. Must be unique within the chain when provided.", + "example": "Example Name", + "type": "string" + }, + "on_error": { + "description": "Error handling policy for this step. One of `\"halt\"` (default), `\"continue\"`, or `\"retry\"`.", + "example": "halt", + "type": "string" + }, + "output_key": { + "description": "Key under which this step's result is stored and addressable by downstream steps. Defaults to `name` when omitted.", + "example": "string", + "type": "string" + }, + "preset_config": { + "description": "Configuration overrides for the preset, using the same shape as the routine-level `preset_config`. You may include an `llm` key to override the agent's default model for this step. `null` if not provided.", + "example": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "properties": { + "instructions": { + "description": "Custom task or behavior instructions for the preset (max 10,000 chars).", + "example": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "type": "string" + }, + "llm": { + "description": "LLM invocation settings (e.g. a `model` override for this routine/step).", + "example": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "properties": { + "model": { + "description": "Provider-prefixed model identifier for this routine or step, e.g. `\"openrouter/anthropic/claude-sonnet-latest\"`. When omitted, the agent's default model is used.", + "example": "openrouter/anthropic/claude-sonnet-latest", + "type": "string" + } + }, + "type": "object" + }, + "session_mode": { + "description": "Session mode: `stateless` (default, new session per trigger) or `session` (find-or-create a persistent session scoped by `session_scope`).", + "example": "stateless", + "type": "string" + }, + "session_scope": { + "description": "When `session_mode` is `session`, controls session scoping: `per_user` (default), `per_key`, `per_org`, or `global`.", + "example": "per_user", + "type": "string" + }, + "structured_message_template_ids": { + "description": "IDs of structured message templates that constrain the agent's responses to predefined structured formats.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "preset_name": { + "description": "Name of the preset to invoke. Required when `handler_type` is `\"preset\"`.", + "example": "Example Name", + "type": "string" + }, + "script": { + "description": "Inline script source code to execute. Used when `handler_type` is `\"script\"` and no `config` is provided.", + "example": "string", + "type": "string" + } + }, + "required": [ + "handler_type" + ], + "type": "object" + }, + "type": "array" + }, + "template": { + "description": "AgentRoutineTemplate config ID (`cfg_...`) or lookup key. When provided, the routine's configuration is re-resolved from the template before applying other param overrides. The routine's `status`, `lookup_key`, and agent attachment are always preserved.", + "example": "string", + "type": "string" + }, + "trigger_context": { + "description": "Updated trigger context. One of `\"chat_session\"` or `\"event\"`.", + "example": "string", + "type": "string" + }, + "user": { + "description": "Optional co-owner user ID (`usr_...`) to set on the routine. Must be supplied explicitly — the caller's identity is never auto-stamped. Omit to leave the existing value unchanged; send `null` (or an empty string) to clear the current co-owner.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRoutine" + } + } + }, + "description": "The updated routine." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Routine not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Update a routine", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_routines/{routine}/activate": { + "post": { + "description": "Sets the routine's status to `\"active\"`, enabling it to process events or run\non its configured schedule. Only routines that have a workflow config attached\ncan be activated; attempting to activate a routine with no config returns 422.\n\nScheduled routines must be configured to run no more frequently than once per\nhour. Activation fails with 422 if the cron schedule is more frequent than\nthat limit. Requires app scope.\n", + "operationId": "post_api_v1_agent_routines__routine_activate", + "parameters": [ + { + "description": "Routine ID (`arn_...`) of the routine to activate.", + "example": "string", + "in": "path", + "name": "routine", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRoutine" + } + } + }, + "description": "The updated routine with `status` set to `\"active\"`." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Routine not found" + }, + "422": { + "description": "Unprocessable entity - no workflow config attached" + } + }, + "summary": "Activate a routine", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_routines/{routine}/invoke": { + "post": { + "description": "Triggers an on-demand invocation of the specified routine, dispatching an\nasynchronous agent run and returning a run record immediately. The routine must\nbe active and must have `event_type` set to `\"agentroutine.invoked\"`.\n\nThe routine's `preset_config.session_mode` determines session behavior: each\ncall may create a new session (`\"stateless\"`) or reuse an existing one\n(`\"session\"`). When `session_scope` is `\"per_user\"`, the `user` param is\nrequired for S2S and developer callers; authenticated client callers always\nuse their own identity. When `session_scope` is `\"per_key\"`, `session_key`\nis required.\n\nSupply `idempotency_key` to safely retry invocations — if a completed run\nalready exists for that key a 409 Conflict is returned rather than creating\na duplicate run. Entitlement for LLM calls is checked at request time;\ncustomers on plans that do not include this feature receive 402.\n\nUse `delivery` to propagate the final textual result into a conversation.\n`{\"type\":\"reply\",\"message\":\"msg_...\"}` preserves the message's external\norigin (for example Slack), while `{\"type\":\"thread\",\"thread\":\"thr_...\"}`\nposts without a reply anchor. Chain routines deliver only their final result.\n\nFor workflow-graph routines that dispatch distributed work, pass optional\n`participants` (map of symbolic refs to agent ids, e.g.\n`{\"investigator\":\"agi_...\"}`) as a **top-level** field next to free-form\ninvoke inputs — same shape as automation invoke. Free-form fields stay on\n`event_payload`; participants are stored in the run's top-level\n`participants` field and exposed through workflow system context so\n`embed_agent` nodes can resolve assignees.\n", + "operationId": "post_api_v1_agent_routines__routine_invoke", + "parameters": [ + { + "description": "Routine ID (`arn_...`) or `lookup_key` of the routine to invoke.", + "example": "string", + "in": "path", + "name": "routine", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "delivery": { + "message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "none" + }, + "idempotency_key": "string", + "message": "string", + "metadata": { + "key": "value" + }, + "participants": {}, + "session_key": "string", + "thread_id": "string", + "user": "string" + }, + "properties": { + "delivery": { + "description": "Typed final-result delivery: reply to a `message`, post to a `thread`, or `none` (the default).", + "example": { + "message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "none" + }, + "properties": { + "message": { + "description": "Message ID (`msg_...`) to reply to. Required when `type` is `reply`.", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "Destination thread ID (`thr_...`). Required when `type` is `thread`.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "type": { + "description": "Delivery mode. Use `none` for no delivery, `thread` to post to a conversation, or `reply` to preserve a message reply anchor.", + "enum": [ + "none", + "thread", + "reply" + ], + "example": "none", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "idempotency_key": { + "description": "Unique key used to deduplicate invocations. Resubmitting the same key returns 409 if a completed run already exists.", + "example": "string", + "type": "string" + }, + "message": { + "description": "The user message to send to the agent for this invocation.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this invocation. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "participants": { + "description": "Map of symbolic participant refs to agent ids (`agi_...` or UUID) for distributed embed_agent handoffs. Stored in the run's top-level `participants` field.", + "example": {}, + "type": "object" + }, + "session_key": { + "description": "Arbitrary key used to identify and resume a session when `session_scope` is `\"per_key\"`. Required in that mode.", + "example": "string", + "type": "string" + }, + "thread_id": { + "description": "Thread ID (`thr_...`) to post the preset output into. Omit to skip thread posting.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID to associate with the session. For S2S and developer callers only; authenticated client callers always use their own identity.", + "example": "string", + "type": "string" + } + }, + "required": [ + "message" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRoutineRun" + } + } + }, + "description": "The agent routine run created by this invocation." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "402": { + "description": "Payment required — plan does not allow this feature" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Routine not found" + }, + "409": { + "description": "Idempotency conflict" + }, + "422": { + "description": "Unprocessable entity" + } + }, + "summary": "Invoke a routine", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_routines/{routine}/pause": { + "post": { + "description": "Sets the routine's status to `\"paused\"`, suspending event processing and\nscheduled execution without deleting the routine or its configuration. A\npaused routine can be resumed at any time by calling the activate endpoint.\n\nRequires app scope.\n", + "operationId": "post_api_v1_agent_routines__routine_pause", + "parameters": [ + { + "description": "Routine ID (`arn_...`) of the routine to pause.", + "example": "string", + "in": "path", + "name": "routine", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRoutine" + } + } + }, + "description": "The updated routine with `status` set to `\"paused\"`." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Routine not found" + } + }, + "summary": "Pause a routine", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_routines/{routine}/runs": { + "get": { + "description": "Returns a cursor-paginated list of runs for the specified routine, ordered\nfrom most recent to oldest by default. Use `before_cursor` and `after_cursor`\nto page through results in either direction.\n\nYou can filter runs by status to monitor a specific lifecycle phase. The\nauthenticated principal must have access to the routine's parent app. When\nyour API key is scoped to an app, only runs belonging to that app are\nreturned.\n", + "operationId": "get_api_v1_agent_routines__routine_runs", + "parameters": [ + { + "description": "Routine ID (`rtn_...`) whose runs you want to list.", + "example": "string", + "in": "path", + "name": "routine", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Filter runs by status. One of `\"pending\"`, `\"running\"`, `\"completed\"`, `\"failed\"`, or `\"skipped\"`. Omit to return runs in all statuses.", + "example": "string", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of runs to return per page. Defaults to 50; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor from a previous response's `before_cursor` field. Returns the page of runs older than this cursor.", + "example": "string", + "in": "query", + "name": "before_cursor", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Opaque cursor from a previous response's `after_cursor` field. Returns the page of runs newer than this cursor.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRoutineRunListResponse" + } + } + }, + "description": "Paginated list of routine runs." + }, + "400": { + "description": "Invalid cursor" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Routine not found" + } + }, + "summary": "List runs for a routine", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_sessions": { + "get": { + "description": "Returns a flat list of agent sessions visible to the authenticated app,\nordered by creation time descending. Use the `agent`, `status`, and\n`routine_run` filters to narrow results.\n\nAll filters are optional and can be combined. The `status` and `routine_run`\nparameters each accept multiple values; pass the parameter more than once or\nas a comma-separated array to match any of the supplied values.\n\nRequires an app-scoped API key. Results are limited to sessions that belong\nto agents owned by the authenticated app.\n", + "operationId": "get_api_v1_agent_sessions", + "parameters": [ + { + "description": "Filter by agent IDs (`agi_...`). Omit to return sessions for all agents in the app. Multiple values are OR'd.", + "example": [ + "string" + ], + "in": "query", + "name": "agent", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Filter by one or more session statuses. Accepted values are `\"pending\"`, `\"running\"`, `\"waiting\"`, `\"completed\"`, `\"failed\"`, and `\"cancelled\"`. Omit to return sessions in any status.", + "example": [ + "string" + ], + "in": "query", + "name": "status", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Filter to sessions that were created by the specified routine run IDs. Accepts up to 100 IDs. Omit to return sessions regardless of their originating routine run.", + "example": [ + "string" + ], + "in": "query", + "name": "routine_run", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "When `true`, omits sessions that were created automatically by the platform rather than by your app. Defaults to `false`.", + "example": true, + "in": "query", + "name": "exclude_system", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Maximum number of sessions to return. Defaults to 25; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSessionListResponse" + } + } + }, + "description": "A list of agent sessions matching the supplied filters." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "List agent sessions", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new agent session and enqueues it for execution. The session begins\nin `\"pending\"` status and transitions to `\"running\"` once the platform picks\nit up. Subscribe to the session stream endpoint to receive real-time status\nupdates.\n\nYou must supply the ID of an agent that the authenticated app owns and a\nplain-text `instructions` string describing the task. All other parameters\nare optional and default to the agent's configured limits when omitted.\n\nSet `start_idle` to `true` to create the session without running an opening\nturn — it begins in `\"waiting\"` status and runs its first turn only once you\npost a message (see the message endpoint). Use this when you want the first\nmessage to drive the session instead of the `instructions` alone.\n\nRequires an app-scoped API key. Returns HTTP 201 on success.\n", + "operationId": "post_api_v1_agent_sessions", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "instructions": "string", + "max_runs_per_turn": 1, + "max_tokens": 1, + "max_turns": 1, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "start_idle": true, + "team": "string", + "thread": "string", + "user": "string" + }, + "properties": { + "agent": { + "description": "Agent ID (`agi_...`) of the agent that will execute the session.", + "example": "string", + "type": "string" + }, + "instructions": { + "description": "Plain-text task description given to the agent as its primary objective for this session.", + "example": "string", + "type": "string" + }, + "max_runs_per_turn": { + "description": "Maximum number of tool invocations allowed within a single agent turn. Defaults to 25.", + "example": 1, + "type": "integer" + }, + "max_tokens": { + "description": "Maximum number of tokens the agent may consume across all turns. Defaults to 20,000.", + "example": 1, + "type": "integer" + }, + "max_turns": { + "description": "Maximum number of agent turns before the session is automatically terminated. Defaults to 100.", + "example": 1, + "type": "integer" + }, + "metadata": { + "description": "Arbitrary key-value metadata to attach to the session. Stored and returned as-is; not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the session. Useful for identifying sessions in the dashboard. `null` if omitted.", + "example": "Example Name", + "type": "string" + }, + "start_idle": { + "description": "When `true`, create the session without running an opening turn. The session starts in `\"waiting\"` status and runs its first turn only when you post a message. Defaults to `false`, which runs an initial turn from `instructions` immediately.", + "example": true, + "type": "boolean" + }, + "team": { + "description": "Team ID (`tea_...`) to associate with this session for access-control and attribution purposes. `null` if omitted.", + "example": "string", + "type": "string" + }, + "thread": { + "description": "Thread ID (`thr_...`) to link this session to an existing conversation thread. `null` if omitted.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID to associate with this session for attribution purposes. `null` if omitted.", + "example": "string", + "type": "string" + } + }, + "required": [ + "agent", + "instructions" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSession" + } + } + }, + "description": "The newly created agent session." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create an agent session", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_sessions/{agent_session}": { + "delete": { + "description": "Permanently deletes an agent session and its associated data. This action is\nirreversible — the session record, its trajectory, and all inbox messages are\nremoved.\n\nTo stop a running session without deleting it, use the cancel endpoint\ninstead. The session must be in a terminal state (`\"completed\"`, `\"failed\"`,\nor `\"cancelled\"`) before it can be deleted; attempting to delete an active\nsession returns 422.\n\nRequires an app-scoped API key. Returns HTTP 204 with no body on success.\n", + "operationId": "delete_api_v1_agent_sessions__agent_session", + "parameters": [ + { + "description": "Agent session ID (`ase_...`) of the session to delete.", + "example": "string", + "in": "path", + "name": "agent_session", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty body. HTTP 204 indicates the session was permanently deleted." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Session not found" + } + }, + "summary": "Delete an agent session", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the agent session identified by `agent_session`. Use this endpoint\nto poll session status or to inspect the final result after execution\ncompletes.\n\nFor real-time updates without polling, subscribe to the session stream\nendpoint instead, which delivers server-sent events whenever the session\nstate changes.\n\nRequires an app-scoped API key. The session must belong to an agent owned\nby the authenticated app.\n", + "operationId": "get_api_v1_agent_sessions__agent_session", + "parameters": [ + { + "description": "Agent session ID (`ase_...`) of the session to retrieve.", + "example": "string", + "in": "path", + "name": "agent_session", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSession" + } + } + }, + "description": "The requested agent session." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Session not found" + } + }, + "summary": "Retrieve an agent session", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "patch": { + "description": "Updates the mutable fields of an agent session. Currently only `metadata`\ncan be changed; supply any key-value pairs you want to store alongside the\nsession. Omitting `metadata` leaves it unchanged.\n\nThis endpoint may be called while the session is in any status, including\nwhile it is actively running.\n\nRequires an app-scoped API key. The session must belong to an agent owned\nby the authenticated app.\n", + "operationId": "patch_api_v1_agent_sessions__agent_session", + "parameters": [ + { + "description": "Agent session ID (`ase_...`) of the session to update.", + "example": "string", + "in": "path", + "name": "agent_session", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "metadata": { + "key": "value" + } + }, + "properties": { + "metadata": { + "description": "Arbitrary key-value metadata to attach to the session. Replaces the existing metadata map entirely. Omit to leave the current metadata unchanged.", + "example": { + "key": "value" + }, + "type": "object" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSession" + } + } + }, + "description": "The agent session with the updated fields applied." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Session not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Update an agent session", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_sessions/{agent_session}/cancel": { + "post": { + "description": "Requests cancellation of an active agent session. The session status is set\nto `\"cancelled\"` and any in-progress agent turn is interrupted as soon as the\nplatform can safely stop it.\n\nIf the session is already in a terminal state (`\"completed\"`, `\"failed\"`, or\n`\"cancelled\"`), the call succeeds and returns the session unchanged — it is\nsafe to call this endpoint more than once.\n\nRequires an app-scoped API key. The session must belong to an agent owned by\nthe authenticated app.\n", + "operationId": "post_api_v1_agent_sessions__agent_session_cancel", + "parameters": [ + { + "description": "Agent session ID (`ase_...`) of the session to cancel.", + "example": "string", + "in": "path", + "name": "agent_session", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSession" + } + } + }, + "description": "The agent session after the cancellation request is applied." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Session not found" + } + }, + "summary": "Cancel an agent session", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_sessions/{agent_session}/message": { + "post": { + "description": "Appends a message to the inbox of the specified agent session. The agent\nreads inbox messages at the start of each turn; sending a message to a\n`\"waiting\"` session signals it to resume execution.\n\nUse `role` to identify the sender type. The default role is `\"user\"`.\nArbitrary key-value metadata may be attached to the message for tracking\nor display purposes.\n\nRequires an app-scoped API key. The session must belong to an agent owned\nby the authenticated app.\n", + "operationId": "post_api_v1_agent_sessions__agent_session_message", + "parameters": [ + { + "description": "Agent session ID (`ase_...`) of the session whose inbox should receive the message.", + "example": "string", + "in": "path", + "name": "agent_session", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "content": "string", + "metadata": { + "key": "value" + }, + "role": "string" + }, + "properties": { + "content": { + "description": "Plain-text body of the message to deliver to the agent.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata to attach to the message. Stored and returned as-is; not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "role": { + "description": "Role of the message sender. Typically `\"user\"` or `\"tool\"`. Defaults to `\"user\"`.", + "example": "string", + "type": "string" + } + }, + "required": [ + "content" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSession" + } + } + }, + "description": "The agent session with the new message appended to its `inbox`." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Session not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Send a message to an agent session", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_sessions/{agent_session}/stream": { + "get": { + "description": "Opens a Server-Sent Events connection that emits a `session_update` event\nwhenever the agent session's status changes, replaying the current status on\nconnect and closing on a terminal status (`completed`, `failed`, `cancelled`).\n", + "operationId": "get_api_v1_agent_sessions__agent_session_stream", + "parameters": [ + { + "description": "ID of the agent session to stream.", + "example": "string", + "in": "path", + "name": "agent_session", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "text/event-stream": { + "schema": { + "$ref": "#/components/schemas/AgentSession" + } + } + }, + "description": "Server-Sent Events stream" + }, + "404": { + "description": "Session not found" + } + }, + "summary": "Stream agent session status", + "x-auth": [ + "publishable_key", + "bearer" + ], + "x-sdk-streaming": { + "events": { + "session_update": { + "$ref": "#/components/schemas/AgentSession" + } + }, + "type": "sse" + } + } + }, + "/api/v1/agent_skills": { + "get": { + "description": "Returns all agent skills belonging to the authenticated app. Results include\nskills in any status (`\"active\"` or `\"inactive\"`). Use the `agent` filter to\nnarrow results to one or more specific agents.\n\nRequires an app-scoped API key. Supplying one or more `agent` values that\ncannot be resolved within the app returns 404.\n", + "operationId": "get_api_v1_agent_skills", + "parameters": [ + { + "description": "Filter results to skills belonging to the specified agent(s). Accepts one or more agent IDs (`agt_...`) or lookup keys. Omit to return skills across all agents in the app.", + "example": [ + "string" + ], + "in": "query", + "name": "agent", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSkillList" + } + } + }, + "description": "List of agent skills matching the query." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + } + }, + "summary": "List agent skills", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Attaches a skill config to an agent, creating an agent skill record and\nreturning it with an initial status of `\"inactive\"`. Use the activate\nendpoint to make the skill available during agent runs.\n\nRequires an app-scoped API key. The `agent` and `config` must both belong\nto the authenticated app. Supplying a `config` that does not exist within\nthe app returns 422. Returns 201 on success.\n", + "operationId": "post_api_v1_agent_skills", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "config": "string", + "instruction": "string", + "metadata": { + "key": "value" + } + }, + "properties": { + "agent": { + "description": "Agent ID (`agt_...`) to attach the skill to.", + "example": "string", + "type": "string" + }, + "config": { + "description": "Skill config ID (`cfg_...`) that defines the skill's behavior. Must belong to the authenticated app.", + "example": "string", + "type": "string" + }, + "instruction": { + "description": "Optional plain-text instruction override. When supplied, replaces the default instruction from the skill config for this agent.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata to store with the agent skill. Useful for tracking provisioning context or custom labels.", + "example": { + "key": "value" + }, + "type": "object" + } + }, + "required": [ + "agent", + "config" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSkill" + } + } + }, + "description": "The newly created agent skill record." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Enable a skill on an agent", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_skills/{agent_skill}": { + "delete": { + "description": "Permanently removes the specified agent skill, detaching the skill config\nfrom the agent. This action cannot be undone. To temporarily stop a skill\nfrom being invoked without removing it, use the deactivate endpoint instead.\n\nRequires an app-scoped API key. Returns 204 No Content on success.\n", + "operationId": "delete_api_v1_agent_skills__agent_skill", + "parameters": [ + { + "description": "Agent skill ID (`ask_...`) to remove.", + "example": "string", + "in": "path", + "name": "agent_skill", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "No content" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Not found" + } + }, + "summary": "Remove a skill from an agent", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the agent skill identified by its ID. The skill must belong to\nthe authenticated app's scope.\n\nRequires an app-scoped API key.\n", + "operationId": "get_api_v1_agent_skills__agent_skill", + "parameters": [ + { + "description": "Agent skill ID (`ask_...`) to retrieve.", + "example": "string", + "in": "path", + "name": "agent_skill", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSkill" + } + } + }, + "description": "The requested agent skill." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Not found" + } + }, + "summary": "Retrieve an agent skill", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "patch": { + "description": "Updates one or more mutable fields on the specified agent skill. All\nparameters are optional; supply only the fields you want to change.\n\nWhen `template` is provided, the platform re-resolves that skill template\nand re-points the skill's underlying config in place. The skill's current\nstatus is preserved. Any `instruction` or `metadata` supplied alongside\n`template` override the template's defaults.\n\nRequires an app-scoped API key. The skill must belong to the authenticated\napp's scope.\n", + "operationId": "patch_api_v1_agent_skills__agent_skill", + "parameters": [ + { + "description": "Agent skill ID (`ask_...`) to update.", + "example": "string", + "in": "path", + "name": "agent_skill", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "instruction": "string", + "metadata": { + "key": "value" + }, + "template": "string" + }, + "properties": { + "instruction": { + "description": "Plain-text instruction override for this agent skill. Replaces the default instruction from the skill config. Omit to leave the current value unchanged.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata to store with the agent skill. Omit to leave the current value unchanged.", + "example": { + "key": "value" + }, + "type": "object" + }, + "template": { + "description": "Agent skill template config ID (`cfg_...`), virtual path, or lookup key. When supplied, re-resolves the template and updates the skill's underlying config in place, refreshing template provenance while preserving the skill's current status. Any `instruction` or `metadata` values provided alongside `template` override the template defaults.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSkill" + } + } + }, + "description": "The agent skill after the update has been applied." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Update an agent skill", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_skills/{agent_skill}/activate": { + "post": { + "description": "Sets the status of the specified agent skill to `\"active\"`, allowing the\nskill to be invoked during agent runs. The skill must already exist on the\nagent (created via the enable endpoint) and belong to the authenticated\napp's scope.\n\nRequires an app-scoped API key. Activating a skill that is already active\nis a no-op and returns the skill unchanged.\n", + "operationId": "post_api_v1_agent_skills__agent_skill_activate", + "parameters": [ + { + "description": "Agent skill ID (`ask_...`) to activate.", + "example": "string", + "in": "path", + "name": "agent_skill", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSkill" + } + } + }, + "description": "The agent skill after activation, with `status` set to `\"active\"`." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Not found" + } + }, + "summary": "Activate an agent skill", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_skills/{agent_skill}/deactivate": { + "post": { + "description": "Sets the status of the specified agent skill to `\"inactive\"`, preventing\nthe skill from being invoked during future agent runs. The skill record\nis preserved and can be reactivated at any time.\n\nRequires an app-scoped API key. Deactivating a skill that is already\ninactive is a no-op and returns the skill unchanged.\n", + "operationId": "post_api_v1_agent_skills__agent_skill_deactivate", + "parameters": [ + { + "description": "Agent skill ID (`ask_...`) to deactivate.", + "example": "string", + "in": "path", + "name": "agent_skill", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSkill" + } + } + }, + "description": "The agent skill after deactivation, with `status` set to `\"inactive\"`." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Not found" + } + }, + "summary": "Deactivate an agent skill", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_tools": { + "get": { + "description": "Returns all tools for the authenticated app, optionally filtered by agent\nor tool kind. Both explicitly created tools and tools derived from connected\nintegrations (installation-sourced tools) are included in the response.\n\nInstallation-sourced tools appear with `source: \"installation\"` and\n`status: \"active\"`. They are synthesized at request time from connected\nintegrations and do not have a persistent tool ID of the `atl_...` form;\ntheir `id` is a composite of the installation ID and server tool type.\n\nUse the `agent` filter to retrieve tools for a specific agent. Supplying an\n`agent` ID that does not belong to the authenticated app returns 404.\nRequires app scope.\n", + "operationId": "get_api_v1_agent_tools", + "parameters": [ + { + "description": "Filter results to tools belonging to these agents (`agi_...`). Omit to return tools across all agents in the app. Multiple values are OR'd.", + "example": [ + "string" + ], + "in": "query", + "name": "agent", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Filter by tool kind. One of `\"builtin\"` or `\"custom\"`. Omit to return tools of all kinds.", + "example": "string", + "in": "query", + "name": "kind", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentToolListResponse" + } + } + }, + "description": "List of tools matching the supplied filters." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + } + }, + "summary": "List agent tools", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_tools/catalog": { + "get": { + "description": "Returns the full catalog of built-in tool categories available on the platform.\nEach entry describes a tool type that can be added to an agent, including its\nkey, display label, configuration schema, and the individual tools it exposes\nto the LLM.\n\nThe catalog is global — it is not filtered by app or agent. Use the `key` from\neach entry as the `builtin_tool_key` when creating a built-in tool. Entries\nwhose `requires_integration` is `true` require a connected integration before\nthe tool can be activated on an agent.\n\nRequires app scope.\n", + "operationId": "get_api_v1_agent_tools_catalog", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/BuiltinToolCatalogEntry" + }, + "type": "array" + } + } + }, + "description": "Array of built-in tool catalog entries, one per registered tool category." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + } + }, + "summary": "List built-in tool categories", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_tools/{tool}": { + "delete": { + "description": "Permanently removes a tool from the agent. This action cannot be undone.\n\nBoth `\"draft\"` and `\"active\"` tools can be deleted. If you only want to\nstop the agent from using a tool without removing it, use the deactivate\nendpoint instead.\n\nRequires app scope. The authenticated caller must own the tool's parent agent.\n", + "operationId": "delete_api_v1_agent_tools__tool", + "parameters": [ + { + "description": "Tool ID (`atl_...`) of the tool to delete.", + "example": "string", + "in": "path", + "name": "tool", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response. Returns HTTP 204 on success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Tool not found" + } + }, + "summary": "Delete an agent tool", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the tool identified by `tool`. The tool must belong to an agent\nowned by the authenticated app.\n\nUse this endpoint to inspect a tool's current configuration, status, and\nmetadata. To retrieve all tools for an agent or app, use the list endpoint.\nRequires app scope.\n", + "operationId": "get_api_v1_agent_tools__tool", + "parameters": [ + { + "description": "Tool ID (`atl_...`) of the tool to retrieve.", + "example": "string", + "in": "path", + "name": "tool", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentTool" + } + } + }, + "description": "The requested tool." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Tool not found" + } + }, + "summary": "Retrieve an agent tool", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "patch": { + "description": "Updates the configuration of an existing tool. All parameters are optional;\nsupply only the fields you want to change. Unspecified fields are left as-is.\n\nYou can update both `\"draft\"` and `\"active\"` tools. Updating an active tool\ntakes effect on the next agent run; any run already in progress continues\nwith the configuration it loaded at start.\n\nSupplying `template` re-resolves the referenced AgentToolTemplate and patches\nthe tool in place, preserving its `status`, `lookup_key`, `kind`, and agent\nassociation. Any other params you supply alongside `template` override the\ntemplate defaults.\n\nRequires app scope. The authenticated caller must own the tool's parent agent.\n", + "operationId": "patch_api_v1_agent_tools__tool", + "parameters": [ + { + "description": "Tool ID (`atl_...`) of the tool to update.", + "example": "string", + "in": "path", + "name": "tool", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "async": true, + "builtin_tool_config": {}, + "config": "string", + "description": "An example description.", + "handler_type": "string", + "instruction": "string", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "name_prefix": "string", + "parameters": {}, + "parameters_config": "string", + "template": "string" + }, + "properties": { + "async": { + "description": "When `true`, the tool executes asynchronously and the agent does not block waiting for a result. Applies to `\"custom\"` tools.", + "example": true, + "type": "boolean" + }, + "builtin_tool_config": { + "description": "Configuration object for the built-in tool. Shape is defined by the catalog entry's `config_schema` for the tool's `builtin_tool_key`. Applies to `\"builtin\"` tools.", + "example": {}, + "type": "object" + }, + "config": { + "description": "Config ID (`cfg_...`) referencing the script or workflow graph that implements the tool handler. Applies to `\"custom\"` tools.", + "example": "string", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the tool does, shown to the LLM as context. Applies primarily to `\"custom\"` tools.", + "example": "An example description.", + "type": "string" + }, + "handler_type": { + "description": "Execution handler for the tool. One of `\"script\"` or `\"workflow_graph\"`. Applies to `\"custom\"` tools.", + "example": "string", + "type": "string" + }, + "instruction": { + "description": "Additional natural-language instruction provided to the LLM describing when and how to call this tool. Supplements the tool's `description`.", + "example": "string", + "type": "string" + }, + "lookup_key": { + "description": "Stable identifier you can use to look up this tool without its ID. Must be unique within the app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata to attach to the tool. Replaces the existing metadata when supplied.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Display name for the tool. Applies to `\"custom\"` tools.", + "example": "Example Name", + "type": "string" + }, + "name_prefix": { + "description": "Per-instance namespace for built-in tools that support multiple instances per agent. Stamped onto LLM-facing tool names (e.g. `\"org\"` produces `\"org_knowledge_search\"`). Must match `^[a-z][a-z0-9_]*$` and be at most 24 characters.", + "example": "string", + "type": "string" + }, + "parameters": { + "description": "JSON Schema object describing the tool's input parameters. Replaces the existing parameter schema when supplied.", + "example": {}, + "type": "object" + }, + "parameters_config": { + "description": "Config ID (`cfg_...`) referencing a reusable JSON Schema definition for this tool's input parameters. Takes precedence over an inline `parameters` value.", + "example": "string", + "type": "string" + }, + "template": { + "description": "Config ID or lookup key of an AgentToolTemplate. When provided, re-resolves the template and patches the tool in place, preserving its `status`, `lookup_key`, `kind`, and agent association. Other params you supply alongside `template` override the template defaults.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentTool" + } + } + }, + "description": "The updated tool." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Tool not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Update an agent tool", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_tools/{tool}/activate": { + "post": { + "description": "Transitions a tool from `\"draft\"` status to `\"active\"`, making it available\nfor the agent to use during runs. Only tools in `\"draft\"` status can be\nactivated; calling this on an already-active tool is a no-op that returns the\ncurrent tool state.\n\nActivation validates that all required configuration is present. For built-in\ntools, this means the `builtin_tool_key` must resolve to a registered tool\ntype and any required integration must be connected. Returns 422 if\nprerequisite checks fail.\n\nRequires app scope. The authenticated caller must own the tool's parent agent.\n", + "operationId": "post_api_v1_agent_tools__tool_activate", + "parameters": [ + { + "description": "Tool ID (`atl_...`) of the tool to activate.", + "example": "string", + "in": "path", + "name": "tool", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentTool" + } + } + }, + "description": "The updated tool with `status: \"active\"`." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Tool not found" + }, + "422": { + "description": "Cannot activate tool" + } + }, + "summary": "Activate an agent tool", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agent_tools/{tool}/deactivate": { + "post": { + "description": "Transitions a tool from `\"active\"` status back to `\"draft\"`, removing it\nfrom the set of tools the agent can use during future runs. Calling this on a\ntool that is already in `\"draft\"` status is a no-op that returns the current\ntool state.\n\nDeactivation does not delete the tool or its configuration. To remove the\ntool permanently, use the delete endpoint.\n\nRequires app scope. The authenticated caller must own the tool's parent agent.\n", + "operationId": "post_api_v1_agent_tools__tool_deactivate", + "parameters": [ + { + "description": "Tool ID (`atl_...`) of the tool to deactivate.", + "example": "string", + "in": "path", + "name": "tool", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentTool" + } + } + }, + "description": "The updated tool with `status: \"draft\"`." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Tool not found" + } + }, + "summary": "Deactivate an agent tool", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents": { + "get": { + "description": "Returns a paginated list of agents visible to the authenticated caller. Results are\nordered by creation time descending.\n\nUse `search` to filter by name, org, team, or owner fields. Use `user` or `org_id`\nto scope the list to a specific owner. Use `template_config` to find agents whose\nlast applied template matches a given config ID. Use `solution_config` to find\nagents whose last applied template was imported as part of any of the given\nSolution config IDs.\n\nPagination is page-based: pass `page` and `page_size` to navigate through large\nresult sets. When called under a developer app scope, only agents belonging to that\napp are returned.\n", + "operationId": "get_api_v1_agents", + "parameters": [ + { + "description": "Page number to retrieve, 1-indexed. Defaults to `1`.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of agents to return per page. Defaults to `25`.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Free-text search string matched against the agent name, org, team, and owner fields.", + "example": "string", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) to filter by. Returns only agents owned by this user.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Organization ID (`org_...`) to filter by. Returns only agents owned by this org.", + "example": "string", + "in": "query", + "name": "org_id", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Config ID (`cfg_...`) or `lookup_key` of an AgentTemplate. Returns only agents whose last applied template matches.", + "example": "string", + "in": "query", + "name": "template_config", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Solution config IDs (`cfg_...`) to filter by. Returns only agents whose last applied template was imported as part of any of the listed Solutions. Pass one or more IDs.", + "example": [ + "string" + ], + "in": "query", + "name": "solution_config", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentListResponse" + } + } + }, + "description": "Paginated list of agents matching the supplied filters." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + } + }, + "summary": "List agents", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new agent. Supports two mutually exclusive provisioning modes.\n\n**Template mode** — pass `template` with the ID or `lookup_key` of an existing\nAgentTemplate config. The agent's tools, routines, skills, and installations are\nprovisioned from that template's `config_ref` entries.\n\n**Bundle mode** — pass `template_bundle` with a self-contained install payload\n(AgentTemplate body plus every skill, script, and config it references). The entire\nbundle commits in a single transaction; any failure rolls back the whole install and\nthe response includes `installed_configs[]` — one entry per persisted config.\n\nPass exactly one of `template` or `template_bundle`. If neither is supplied, `name`\nis required and a blank agent is created. Requires authentication; when called under\na developer app scope (`/developer/apps/:app/...`), the caller must hold the app scope\nfor the target app.\n", + "operationId": "post_api_v1_agents", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "description": "An example description.", + "email": "user@example.com", + "identity": "string", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "model": "string", + "name": "Example Name", + "org": "string", + "originator": "string", + "phone_number": "+15555550123", + "profile_picture": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "team": "string", + "template": "string", + "template_bundle": { + "configs": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "tools/my-tool.yaml" + } + ], + "lookup_key_suffix": "string", + "setup_actions": [ + { + "depends_on": [ + "string" + ], + "description": "An example description.", + "kind": "env_var", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "title": "Example Title", + "verify_config": { + "key": "value" + } + } + ], + "skills": [ + { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "relative_path": "skills/my-skill/SKILL.md" + } + ], + "template": { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + } + }, + "user": "string" + }, + "properties": { + "acl": { + "description": "Access control list controlling which users, teams, or orgs can read or manage this agent.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "description": { + "description": "Human-readable description of what the agent does.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address assigned to the agent. Used as the agent's contact identity.", + "example": "user@example.com", + "type": "string" + }, + "identity": { + "description": "System-prompt identity string describing who the agent is. Passed verbatim to the model on each conversation turn.", + "example": "string", + "type": "string" + }, + "lookup_key": { + "description": "Stable, unique slug used to look up this agent by name instead of ID. Must be unique within the owning app or org.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value map stored on the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "model": { + "description": "Default AI model identifier for this agent, e.g. `claude-sonnet-4-5`. Overridden per-request when the caller specifies a model.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Display name for the agent. Required when neither `template` nor `template_bundle` is provided.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that should own this agent. Mutually exclusive with `team` and `user`.", + "example": "string", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author of the agent, e.g. a user ID, a deploy pipeline, or a slug.", + "example": "string", + "type": "string" + }, + "phone_number": { + "description": "Phone number assigned to the agent in E.164 format, e.g. `+15550001234`.", + "example": "+15555550123", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture to attach to the agent. All three subfields are required when this object is present.", + "example": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "properties": { + "data": { + "description": "Base64-encoded binary content of the image.", + "example": "string", + "type": "string" + }, + "filename": { + "description": "Original filename of the image, e.g. `avatar.png`.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `image/png` or `image/jpeg`.", + "example": "application/json", + "type": "string" + } + }, + "required": [ + "data", + "mime_type", + "filename" + ], + "type": "object" + }, + "team": { + "description": "Team ID (`team_...`) that should own this agent. Mutually exclusive with `org` and `user`.", + "example": "string", + "type": "string" + }, + "template": { + "description": "ID (`cfg_...`) or `lookup_key` of an existing AgentTemplate config to provision from. Mutually exclusive with `template_bundle`.", + "example": "string", + "type": "string" + }, + "template_bundle": { + "description": "Self-contained install bundle containing an AgentTemplate plus all referenced skills and configs. The entire bundle is committed atomically. Mutually exclusive with `template`.", + "example": { + "configs": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "tools/my-tool.yaml" + } + ], + "lookup_key_suffix": "string", + "setup_actions": [ + { + "depends_on": [ + "string" + ], + "description": "An example description.", + "kind": "env_var", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "title": "Example Title", + "verify_config": { + "key": "value" + } + } + ], + "skills": [ + { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "relative_path": "skills/my-skill/SKILL.md" + } + ], + "template": { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + } + }, + "properties": { + "configs": { + "description": "Additional configuration resources (scripts, model configs, routine templates) referenced by `config_ref` entries in the template.", + "example": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "tools/my-tool.yaml" + } + ], + "items": { + "description": "A supporting configuration resource included in a template bundle, such as a script, model config, or routine template referenced by the agent template.", + "example": { + "content": "string", + "content_type": "application/json", + "relative_path": "tools/my-tool.yaml" + }, + "properties": { + "content": { + "description": "Full text content of the configuration file.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the configuration content, e.g. `\"application/x-yaml\"` or `\"application/json\"`. `null` if not specified.", + "example": "application/json", + "type": "string" + }, + "relative_path": { + "description": "Bundle-relative path to this config file. The path determines the config kind and its storage identity within the installation.", + "example": "tools/my-tool.yaml", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "lookup_key_suffix": { + "description": "A string appended to the lookup key of every uploaded config and rewritten into every `config_ref` in the template body. Should be stable for a given install and unique across installs to avoid key collisions.", + "example": "string", + "type": "string" + }, + "setup_actions": { + "description": "Post-install checklist items created alongside the agent. Each action is inserted as a pending setup step that the user must complete before the agent is fully operational.", + "example": [ + { + "depends_on": [ + "string" + ], + "description": "An example description.", + "kind": "env_var", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "title": "Example Title", + "verify_config": { + "key": "value" + } + } + ], + "items": { + "description": "A post-install setup checklist item that the user must complete before the installed agent is fully operational.", + "example": { + "depends_on": [ + "string" + ], + "description": "An example description.", + "kind": "env_var", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "title": "Example Title", + "verify_config": { + "key": "value" + } + }, + "properties": { + "depends_on": { + "description": "List of other setup action identifiers that must be completed before this action becomes actionable.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "description": { + "description": "Markdown-formatted instructions or context shown beneath the checklist item. `null` if not provided.", + "example": "An example description.", + "type": "string" + }, + "kind": { + "description": "Category of setup step. One of `\"env_var\"` (configure an environment variable), `\"install\"` (complete an installation step), `\"custom\"` (a user-defined action), or `\"integration\"` (authorize an OAuth-backed MCP server integration).", + "example": "env_var", + "type": "string" + }, + "params": { + "description": "Kind-specific configuration for the action. For `\"env_var\"` steps this typically includes `key` and `scope`; for `\"install\"` steps it includes `installation_kind`; for `\"integration\"` steps it includes `mcp_server_ref`. Shape varies by `kind`.", + "example": { + "key": "value" + }, + "type": "object" + }, + "required": { + "description": "When `true`, this action must be completed before the checklist progress bar reaches 100%. Defaults to `true`.", + "example": true, + "type": "boolean" + }, + "sort_order": { + "description": "Numeric sort position controlling the display order of this action in the checklist. Defaults to `0` when not specified.", + "example": 1, + "type": "integer" + }, + "title": { + "description": "Short human-readable label displayed in the setup checklist.", + "example": "Example Title", + "type": "string" + }, + "verify_config": { + "description": "Configuration passed to the runtime verifier to determine whether the action has been completed, e.g. `{\"type\": \"secret_present\"}`. `null` if no automated verification is configured.", + "example": { + "key": "value" + }, + "type": "object" + } + }, + "required": [ + "kind", + "title" + ], + "type": "object" + }, + "type": "array" + }, + "skills": { + "description": "Skill bundles referenced by the template. Each entry includes the skill root and any supporting files.", + "example": [ + { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "relative_path": "skills/my-skill/SKILL.md" + } + ], + "items": { + "description": "A skill to install as part of a template bundle, consisting of a root `SKILL.md` definition and any accompanying support files.", + "example": { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "relative_path": "skills/my-skill/SKILL.md" + }, + "properties": { + "content": { + "description": "Full text content of the `SKILL.md` file.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the `SKILL.md` content. Defaults to `text/markdown` when omitted.", + "example": "application/json", + "type": "string" + }, + "files": { + "description": "Additional files nested inside the skill folder, each with its own path and content.", + "example": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "items": { + "description": "A single file nested inside a skill folder, included as part of an install bundle.", + "example": { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + }, + "properties": { + "content": { + "description": "Full text content of the file.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the file content. Defaults to a value inferred from the file extension when omitted.", + "example": "application/json", + "type": "string" + }, + "relative_path": { + "description": "Path of this file relative to the skill folder root, e.g. `\"skills/my-skill/helpers.md\"`.", + "example": "skills/my-skill/helpers.md", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "relative_path": { + "description": "Bundle-relative path to the skill root, which must end in `/SKILL.md` (e.g. `\"skills/my-skill/SKILL.md\"`).", + "example": "skills/my-skill/SKILL.md", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "template": { + "description": "The agent template definition to install, including its path and raw content.", + "example": { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + }, + "properties": { + "content": { + "description": "Full text content of the agent template file, typically a YAML document.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the template content. Defaults to `application/x-yaml` when omitted.", + "example": "application/json", + "type": "string" + }, + "relative_path": { + "description": "Bundle-relative path to the template file, used to derive its storage identity (e.g. `\"agent.yaml\"`).", + "example": "agent.yaml", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + } + }, + "required": [ + "template" + ], + "type": "object" + }, + "user": { + "description": "User ID (`usr_...`) that should own this agent. Mutually exclusive with `org` and `team`.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentCreateResponse" + } + } + }, + "description": "The newly created agent. When `template_bundle` was supplied, the response also includes `installed_configs[]` — one entry per persisted config object, with `key` echoing the caller-supplied input identifier." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden — app scope required" + }, + "404": { + "description": "Template not found" + }, + "409": { + "description": "Conflict" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create an agent", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}": { + "delete": { + "description": "Permanently deletes an agent and all of its associated resources. This action cannot\nbe undone.\n\nThe authenticated caller must own the agent or hold sufficient permissions within its\nowning org or team. When called under a developer app scope, the caller must hold the\napp scope for the target app.\n", + "operationId": "delete_api_v1_agents__agent", + "parameters": [ + { + "description": "ID (`agi_...`) or `lookup_key` of the agent to delete.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty body. Returns HTTP 204 on success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Permission denied. The connected account may not have the required permissions. Try reconnecting your account." + }, + "404": { + "description": "Agent not found" + } + }, + "summary": "Delete an agent", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the agent identified by ID or `lookup_key`. The authenticated caller must\nown the agent or hold sufficient permissions within its owning org or team.\n\nWhen called under a developer app scope, the agent must belong to that app. Use the\nlist endpoint to retrieve many agents at once.\n", + "operationId": "get_api_v1_agents__agent", + "parameters": [ + { + "description": "ID (`agi_...`) or `lookup_key` of the agent to retrieve.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Agent" + } + } + }, + "description": "The requested agent." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + } + }, + "summary": "Retrieve an agent", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "patch": { + "description": "Updates one or more fields on an existing agent. Only the fields you supply are\nchanged; omitted fields retain their current values.\n\nTo clear the agent's default model, pass `model` as an empty string. The\nauthenticated caller must own the agent or hold write permissions within its owning\norg or team. When called under a developer app scope, the caller must hold the app\nscope for the target app.\n", + "operationId": "patch_api_v1_agents__agent", + "parameters": [ + { + "description": "ID (`agi_...`) or `lookup_key` of the agent to update.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "description": "An example description.", + "email": "user@example.com", + "identity": "string", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "model": "string", + "name": "Example Name", + "org": "string", + "originator": "string", + "phone_number": "+15555550123", + "profile_picture": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "team": "string", + "user": "string" + }, + "properties": { + "acl": { + "description": "Replacement access control list. Fully replaces the existing ACL.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "description": { + "description": "New description of what the agent does. Pass an empty string to clear it.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "New email address for the agent.", + "example": "user@example.com", + "type": "string" + }, + "identity": { + "description": "Replacement identity system-prompt string describing who the agent is.", + "example": "string", + "type": "string" + }, + "lookup_key": { + "description": "New `lookup_key` slug. Must be unique within the owning app or org.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Replacement key-value metadata map. The entire map is replaced, not merged.", + "example": { + "key": "value" + }, + "type": "object" + }, + "model": { + "description": "New default AI model identifier, e.g. `claude-sonnet-4-5`. Pass an empty string to clear the agent's default model.", + "example": "string", + "type": "string" + }, + "name": { + "description": "New display name for the agent.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) to transfer ownership to.", + "example": "string", + "type": "string" + }, + "originator": { + "description": "Replacement originator label identifying the source or author of the agent.", + "example": "string", + "type": "string" + }, + "phone_number": { + "description": "New phone number for the agent in E.164 format, e.g. `+15550001234`.", + "example": "+15555550123", + "type": "string" + }, + "profile_picture": { + "description": "Replacement profile picture. All three subfields are required when this object is present.", + "example": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "properties": { + "data": { + "description": "Base64-encoded binary content of the image.", + "example": "string", + "type": "string" + }, + "filename": { + "description": "Original filename of the image, e.g. `avatar.png`.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `image/png` or `image/jpeg`.", + "example": "application/json", + "type": "string" + } + }, + "required": [ + "data", + "mime_type", + "filename" + ], + "type": "object" + }, + "team": { + "description": "Team ID (`team_...`) to transfer ownership to.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) to transfer ownership to.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Agent" + } + } + }, + "description": "The updated agent with all current field values." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Update an agent", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/agent_computers": { + "get": { + "description": "Returns all computers belonging to the authenticated app, ordered by creation\ntime descending. Pass `agent` to scope the results to a single agent's\ncomputers. When `agent` is omitted, computers for all agents in the app are\nreturned.\n\nRequires an app-scoped API key. If the specified agent does not exist or does\nnot belong to the app, the endpoint returns 404.\n", + "operationId": "get_api_v1_agents__agent_agent_computers", + "parameters": [ + { + "description": "Agent IDs (`agi_...`). When provided, only computers belonging to these agents are returned. Multiple values are OR'd.", + "example": [ + "string" + ], + "in": "path", + "name": "agent", + "required": true, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentComputerListResponse" + } + } + }, + "description": "Object containing a `data` array of computer records." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + } + }, + "summary": "List computers", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates and provisions a new computer resource associated with the specified\nagent. The computer is allocated in the requested region (defaulting to `iad`)\nand its status transitions from `provisioning` to `running` once it is ready.\n\nRequires an app-scoped API key. The agent identified by `agent` must belong\nto the same app. Supplying a `lookup_key` lets you retrieve this computer\nlater without storing its ID — the key must be unique within the app.\n", + "operationId": "post_api_v1_agents__agent_agent_computers", + "parameters": [ + { + "description": "Agent ID (`agt_...`). The computer is associated with this agent.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "config": {}, + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "provider": "string", + "region": "string" + }, + "properties": { + "config": { + "description": "Provider-specific configuration for the computer. Supported keys vary by provider. A top-level `provider` takes precedence over `config.provider`.", + "example": {}, + "type": "object" + }, + "lookup_key": { + "description": "Stable, user-defined key for this computer. Must be unique within the app. Use it to look up the computer without storing its ID.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata to attach to the computer. Not interpreted by the platform; returned as-is on all subsequent reads.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the computer.", + "example": "Example Name", + "type": "string" + }, + "provider": { + "description": "Compute backend for the computer: `\"sprites\"` (Fly Sprites, the default) or `\"vercel\"` (Vercel Sandbox). Folded into `config.provider`.", + "example": "string", + "type": "string" + }, + "region": { + "description": "Region in which to provision the computer, e.g. `\"iad\"`. Defaults to `\"iad\"` when omitted.", + "example": "string", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentComputer" + } + } + }, + "description": "The newly provisioned computer." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Provision a computer for an agent", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/agent_env_vars": { + "get": { + "description": "Returns all environment variables defined for the specified agent. Variable\nvalues are always masked in the response; only the last four characters are\nvisible. To inspect a specific variable, use the retrieve endpoint.\n\nThe authenticated user must have access to the agent's parent app. Pass the\napp scope via the `app` parameter when calling with an API key that is scoped\nto a specific app. Results are returned in an unordered flat list.\n", + "operationId": "get_api_v1_agents__agent_agent_env_vars", + "parameters": [ + { + "description": "Agent ID (`agt_...`). Returns environment variables belonging to this agent.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentEnvVarMaskedList" + } + } + }, + "description": "List of environment variables for the agent, with values masked." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Agent not found" + } + }, + "summary": "List an agent's environment variables", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new environment variable for the specified agent. The variable is\nstored securely and the plaintext `value` is never returned after creation;\nsubsequent reads return a masked representation showing only the last four\ncharacters.\n\nThe authenticated user must have access to the agent's parent app. Pass the\napp scope via the `app` parameter when calling with an API key that is scoped\nto a specific app. Each `key` must be unique within the agent; attempting to\ncreate a duplicate key returns a validation error.\n", + "operationId": "post_api_v1_agents__agent_agent_env_vars", + "parameters": [ + { + "description": "Agent ID (`agt_...`). The agent must belong to an app the caller can access.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "description": "An example description.", + "key": "string", + "value": "string" + }, + "properties": { + "description": { + "description": "Optional human-readable note describing what the variable is used for.", + "example": "An example description.", + "type": "string" + }, + "key": { + "description": "Environment variable name, e.g. `WEBHOOK_SECRET`. Must be unique within the agent.", + "example": "string", + "type": "string" + }, + "value": { + "description": "Plaintext secret value to store. The value is encrypted at rest and never returned in full.", + "example": "string", + "type": "string" + } + }, + "required": [ + "key", + "value" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentEnvVarMasked" + } + } + }, + "description": "The newly created environment variable with its value masked." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create an agent environment variable", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/agent_health_actions": { + "get": { + "description": "Returns all health actions associated with a given agent. Health actions\nrepresent required or recommended steps — such as setting environment\nvariables, completing OAuth installations, or running custom verifiers —\nthat an agent needs to reach a healthy state.\n\nResults are not paginated; the full list for the agent is returned. Use\nthe `source`, `status`, and `kind` filters to narrow results to the\nsubset your UI or workflow needs. Multiple values for the same filter\nare treated as OR (e.g. passing two statuses returns actions matching\neither). The caller must be authenticated and scoped to the app that\nowns the agent.\n", + "operationId": "get_api_v1_agents__agent_agent_health_actions", + "parameters": [ + { + "description": "Agent ID (`agt_...`) or lookup key of the agent whose health actions you want to list.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Filter results to actions from one or more lifecycle stages. Accepted values: `\"setup\"` (actions created during agent installation) and `\"health\"` (ongoing health checks). Omit to return actions from all stages.", + "example": [ + "string" + ], + "in": "query", + "name": "source", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Filter results to actions in one or more statuses. Accepted values: `\"pending\"`, `\"completed\"`, `\"skipped\"`, and `\"degraded\"`. Omit to return actions in all statuses.", + "example": [ + "string" + ], + "in": "query", + "name": "status", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Filter results to actions of one or more kinds. Accepted values: `\"env_var\"` (a required secret or config value), `\"install\"` (an OAuth or integration install step), and `\"custom\"` (a platform-defined check). Omit to return all kinds.", + "example": [ + "string" + ], + "in": "query", + "name": "kind", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HealthActionListResponse" + } + } + }, + "description": "Object containing a `data` array of health action objects for the specified agent." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Agent not found" + } + }, + "summary": "List health actions for an agent", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/agent_installations": { + "get": { + "description": "Returns all installations belonging to the specified agent, across all kinds and\nstates. Use this endpoint to inspect which external services and enablement channels\nan agent is connected to.\n\nResults are scoped to the authenticated app and are returned in an unordered array.\nTo list installations across all agents in an app, use the top-level List\nInstallations endpoint instead. The caller must have app scope for the app that\nowns the agent.\n", + "operationId": "get_api_v1_agents__agent_agent_installations", + "parameters": [ + { + "description": "Agent ID (`agt_...`) whose installations you want to retrieve.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstallationListResponse" + } + } + }, + "description": "The list of installations for the specified agent." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + } + }, + "summary": "List installations for an agent", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new installation for an agent, connecting it to an external service or\nenablement channel via the specified `kind`. The installation begins in a pending\nstate unless an integration is supplied at creation time, in which case it is\nactivated immediately.\n\nSupply `shared_integration` to bind an existing org- or app-level integration, or\nsupply `integration` to create a new integration inline and activate the installation\nin a single request. Supplying both fields returns 422.\n\nUse `lookup_key` to assign a stable identifier you can reference later in knowledge\nsearch `source_refs`. The key must be unique within the app, org, and sandbox\ncombination. The caller must have app scope for the app that owns the agent.\n", + "operationId": "post_api_v1_agents__agent_agent_installations", + "parameters": [ + { + "description": "Agent ID (`agt_...`) that will own this installation.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "config": {}, + "integration": { + "access_token": "string", + "installation_id": "string", + "metadata": { + "key": "value" + }, + "refresh_token": "string", + "workspace_key": "example-slug" + }, + "kind": "string", + "lookup_key": "string", + "shared_integration": "string" + }, + "properties": { + "config": { + "description": "Kind-specific configuration object. Shape varies by `kind`; omit if the kind requires no initial configuration.", + "example": {}, + "type": "object" + }, + "integration": { + "description": "Inline integration fields to create for `integration/*` kinds. When provided, a new Integration record is created and the installation is activated immediately. Mutually exclusive with `shared_integration`.", + "example": { + "access_token": "string", + "installation_id": "string", + "metadata": { + "key": "value" + }, + "refresh_token": "string", + "workspace_key": "example-slug" + }, + "properties": { + "access_token": { + "description": "OAuth access token or static API key used by `oauth` providers to authenticate requests on behalf of the user.", + "example": "string", + "type": "string" + }, + "installation_id": { + "description": "External installation identifier used by `app_installation` providers, e.g. a GitHub App installation ID or a Slack team ID.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary provider-specific metadata, e.g. `{\"bot_user_id\": \"U012AB3CD\"}` for Slack. Stored alongside the integration and made available to connector logic.", + "example": { + "key": "value" + }, + "type": "object" + }, + "refresh_token": { + "description": "OAuth refresh token used to obtain a new `access_token` when the current one expires. Omit for providers that do not issue refresh tokens.", + "example": "string", + "type": "string" + }, + "workspace_key": { + "description": "Provider-specific workspace or team identifier, e.g. a Slack workspace slug. Used to scope the integration to a particular workspace.", + "example": "example-slug", + "type": "string" + } + }, + "type": "object" + }, + "kind": { + "description": "Installation kind that determines the external service being connected. Examples: `\"enablement/github_app\"`, `\"enablement/slack_bot\"`, `\"integration/github\"`, `\"integration/gmail\"`, `\"web/site\"`. Use the List Kinds endpoint to retrieve all supported values.", + "example": "string", + "type": "string" + }, + "lookup_key": { + "description": "Stable identifier you assign to this installation. Propagated to backing context source rows so they can be referenced via knowledge search `source_refs`. Must contain only lowercase letters, numbers, underscores, or hyphens (max 100 characters). Must be unique within the same app, org, and sandbox combination. Omit to skip stable referencing.", + "example": "string", + "type": "string" + }, + "shared_integration": { + "description": "ID of an existing shared org- or app-level integration to bind to this installation. Mutually exclusive with `integration`.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Installation" + } + } + }, + "description": "The newly created installation." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create an installation", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/agent_installations/kinds": { + "get": { + "description": "Returns the publicly available installation kinds supported by the API. Use the\nreturned `kind` values when calling the Create Installation endpoint.\n\nThe list is platform-wide and does not vary by agent. The `agent` parameter is\naccepted for future per-agent filtering but is currently unused. The caller must\nhave app scope to call this endpoint.\n", + "operationId": "get_api_v1_agents__agent_agent_installations_kinds", + "parameters": [ + { + "description": "Agent ID (`agt_...`). Accepted for forward compatibility but currently does not filter the response.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstallationKindListResponse" + } + } + }, + "description": "The list of publicly available installation kinds." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + } + }, + "summary": "List available installation kinds", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/agent_routines": { + "post": { + "description": "Creates a new routine and attaches it to the specified agent. Routines define\nhow an agent responds to events or a cron schedule; the `handler_type` controls\nwhich execution model is used.\n\nThe routine is created in `\"draft\"` status by default. To start processing\nevents immediately, either pass `status: \"active\"` or call the activate\nendpoint after creation. Scheduled routines must run no more frequently than\nonce per hour. Requires app scope.\n", + "operationId": "post_api_v1_agents__agent_agent_routines", + "parameters": [ + { + "description": "Agent ID (`agt_...`) that this routine will be attached to.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "config": "string", + "description": "An example description.", + "event_config": {}, + "event_type": "string", + "handler_type": "string", + "lookup_key": "string", + "message_policy": { + "recipients": [ + "routine_owner", + "run_actor" + ], + "visibility": "private" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "preset_config": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "preset_name": "Example Name", + "schedule": "string", + "script": "string", + "status": "string", + "steps": [ + { + "config": "string", + "handler_type": "preset", + "inputs": {}, + "name": "Example Name", + "on_error": "halt", + "output_key": "string", + "preset_config": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "preset_name": "Example Name", + "script": "string" + } + ], + "trigger_context": "string", + "user": "string" + }, + "properties": { + "acl": { + "description": "Access control list governing who can read or manage this routine.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "config": { + "description": "Workflow config ID (`cfg_...`). Required when `handler_type` is `\"workflow_graph\"`.", + "example": "string", + "type": "string" + }, + "description": { + "description": "Optional human-readable description of what this routine does.", + "example": "An example description.", + "type": "string" + }, + "event_config": { + "description": "Mapping of event types to trigger configuration. Each key is an event type string; each value is an object with a `\"filters\"` map and an optional `\"dedupe_key_path\"` (a JSON path used to deduplicate events, e.g. `\"$.thread.id\"`).", + "example": {}, + "type": "object" + }, + "event_type": { + "description": "Event type that triggers this routine. Deprecated — use `event_config` instead.", + "example": "string", + "type": "string" + }, + "handler_type": { + "description": "Execution model for this routine. One of `\"workflow_graph\"`, `\"script\"`, `\"preset\"`, or `\"chain\"`.", + "example": "string", + "type": "string" + }, + "lookup_key": { + "description": "Stable, unique key you assign to this routine for deterministic lookup. Must be unique within the app.", + "example": "string", + "type": "string" + }, + "message_policy": { + "description": "Visibility and explicit recipient selection for messages emitted by the routine.", + "example": { + "recipients": [ + "routine_owner", + "run_actor" + ], + "visibility": "private" + }, + "properties": { + "recipients": { + "description": "Required and non-empty for private visibility. Sources are additive. Routine owner includes the agent owner and optional user co-owner.", + "example": [ + "routine_owner", + "run_actor" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "visibility": { + "description": "Message visibility. One of `default` or `private`.", + "example": "private", + "type": "string" + } + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value metadata you can attach to the routine. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the routine.", + "example": "Example Name", + "type": "string" + }, + "preset_config": { + "description": "Configuration passed to the preset at runtime. Used when `handler_type` is `\"preset\"`.", + "example": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "properties": { + "instructions": { + "description": "Custom task or behavior instructions for the preset (max 10,000 chars).", + "example": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "type": "string" + }, + "llm": { + "description": "LLM invocation settings (e.g. a `model` override for this routine/step).", + "example": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "properties": { + "model": { + "description": "Provider-prefixed model identifier for this routine or step, e.g. `\"openrouter/anthropic/claude-sonnet-latest\"`. When omitted, the agent's default model is used.", + "example": "openrouter/anthropic/claude-sonnet-latest", + "type": "string" + } + }, + "type": "object" + }, + "session_mode": { + "description": "Session mode: `stateless` (default, new session per trigger) or `session` (find-or-create a persistent session scoped by `session_scope`).", + "example": "stateless", + "type": "string" + }, + "session_scope": { + "description": "When `session_mode` is `session`, controls session scoping: `per_user` (default), `per_key`, `per_org`, or `global`.", + "example": "per_user", + "type": "string" + }, + "structured_message_template_ids": { + "description": "IDs of structured message templates that constrain the agent's responses to predefined structured formats.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "preset_name": { + "description": "Name of the registered preset to use. Required when `handler_type` is `\"preset\"`.", + "example": "Example Name", + "type": "string" + }, + "schedule": { + "description": "Cron expression for time-triggered routines (e.g. `\"0 9 * * 1\"`). Must not be more frequent than once per hour.", + "example": "string", + "type": "string" + }, + "script": { + "description": "Inline script source. Required when `handler_type` is `\"script\"`.", + "example": "string", + "type": "string" + }, + "status": { + "description": "Initial lifecycle status. One of `\"draft\"` or `\"active\"`. Defaults to `\"draft\"`.", + "example": "string", + "type": "string" + }, + "steps": { + "description": "Ordered list of steps for a chain handler. Required when `handler_type` is `\"chain\"`; must be omitted or empty otherwise. Each step must have exactly one handler body field (`preset_name`, `script`, or `config`) matching that step's `handler_type`.", + "example": [ + { + "config": "string", + "handler_type": "preset", + "inputs": {}, + "name": "Example Name", + "on_error": "halt", + "output_key": "string", + "preset_config": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "preset_name": "Example Name", + "script": "string" + } + ], + "items": { + "description": "A single execution step within a chain-routine, describing the handler to invoke and how to handle errors or pass data between steps.", + "example": { + "config": "string", + "handler_type": "preset", + "inputs": {}, + "name": "Example Name", + "on_error": "halt", + "output_key": "string", + "preset_config": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "preset_name": "Example Name", + "script": "string" + }, + "properties": { + "config": { + "description": "ID of a saved config to use as the handler body. Required when `handler_type` is `\"workflow_graph\"`; also accepted for `\"script\"` as an alternative to an inline `script` value.", + "example": "string", + "type": "string" + }, + "handler_type": { + "description": "Execution handler for this step. One of `\"preset\"`, `\"script\"`, or `\"workflow_graph\"`.", + "example": "preset", + "type": "string" + }, + "inputs": { + "description": "Optional key-value map binding outputs from prior steps to this step's input variables.", + "example": {}, + "type": "object" + }, + "name": { + "description": "Optional label for this step. Must be unique within the chain when provided.", + "example": "Example Name", + "type": "string" + }, + "on_error": { + "description": "Error handling policy for this step. One of `\"halt\"` (default), `\"continue\"`, or `\"retry\"`.", + "example": "halt", + "type": "string" + }, + "output_key": { + "description": "Key under which this step's result is stored and addressable by downstream steps. Defaults to `name` when omitted.", + "example": "string", + "type": "string" + }, + "preset_config": { + "description": "Configuration overrides for the preset, using the same shape as the routine-level `preset_config`. You may include an `llm` key to override the agent's default model for this step. `null` if not provided.", + "example": { + "instructions": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "llm": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "session_mode": "stateless", + "session_scope": "per_user", + "structured_message_template_ids": [ + "string" + ] + }, + "properties": { + "instructions": { + "description": "Custom task or behavior instructions for the preset (max 10,000 chars).", + "example": "You are a helpful assistant. Answer questions concisely and cite sources when possible.", + "type": "string" + }, + "llm": { + "description": "LLM invocation settings (e.g. a `model` override for this routine/step).", + "example": { + "model": "openrouter/anthropic/claude-sonnet-latest" + }, + "properties": { + "model": { + "description": "Provider-prefixed model identifier for this routine or step, e.g. `\"openrouter/anthropic/claude-sonnet-latest\"`. When omitted, the agent's default model is used.", + "example": "openrouter/anthropic/claude-sonnet-latest", + "type": "string" + } + }, + "type": "object" + }, + "session_mode": { + "description": "Session mode: `stateless` (default, new session per trigger) or `session` (find-or-create a persistent session scoped by `session_scope`).", + "example": "stateless", + "type": "string" + }, + "session_scope": { + "description": "When `session_mode` is `session`, controls session scoping: `per_user` (default), `per_key`, `per_org`, or `global`.", + "example": "per_user", + "type": "string" + }, + "structured_message_template_ids": { + "description": "IDs of structured message templates that constrain the agent's responses to predefined structured formats.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "preset_name": { + "description": "Name of the preset to invoke. Required when `handler_type` is `\"preset\"`.", + "example": "Example Name", + "type": "string" + }, + "script": { + "description": "Inline script source code to execute. Used when `handler_type` is `\"script\"` and no `config` is provided.", + "example": "string", + "type": "string" + } + }, + "required": [ + "handler_type" + ], + "type": "object" + }, + "type": "array" + }, + "trigger_context": { + "description": "Context in which the routine is triggered. One of `\"chat_session\"` or `\"event\"`. Defaults to `\"event\"`.", + "example": "string", + "type": "string" + }, + "user": { + "description": "Optional co-owner user ID (`usr_...`). When set, that user shares authority over this routine (view/modify/delete) without needing to administer the parent agent. Must be supplied explicitly — the caller's identity is never auto-stamped as co-owner.", + "example": "string", + "type": "string" + } + }, + "required": [ + "name", + "handler_type" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRoutine" + } + } + }, + "description": "The newly created routine." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create a routine", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/agent_tools": { + "get": { + "description": "Returns all tools for the authenticated app, optionally filtered by agent\nor tool kind. Both explicitly created tools and tools derived from connected\nintegrations (installation-sourced tools) are included in the response.\n\nInstallation-sourced tools appear with `source: \"installation\"` and\n`status: \"active\"`. They are synthesized at request time from connected\nintegrations and do not have a persistent tool ID of the `atl_...` form;\ntheir `id` is a composite of the installation ID and server tool type.\n\nUse the `agent` filter to retrieve tools for a specific agent. Supplying an\n`agent` ID that does not belong to the authenticated app returns 404.\nRequires app scope.\n", + "operationId": "get_api_v1_agents__agent_agent_tools", + "parameters": [ + { + "description": "Filter results to tools belonging to these agents (`agi_...`). Omit to return tools across all agents in the app. Multiple values are OR'd.", + "example": [ + "string" + ], + "in": "path", + "name": "agent", + "required": true, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Filter by tool kind. One of `\"builtin\"` or `\"custom\"`. Omit to return tools of all kinds.", + "example": "string", + "in": "query", + "name": "kind", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentToolListResponse" + } + } + }, + "description": "List of tools matching the supplied filters." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + } + }, + "summary": "List agent tools", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new tool and attaches it to the specified agent. Tools can be\neither `\"builtin\"` (a platform-provided capability identified by\n`builtin_tool_key`) or `\"custom\"` (a caller-defined tool with its own name,\ndescription, parameter schema, and handler).\n\nNew tools are created in `\"draft\"` status by default unless `status:\n\"active\"` is explicitly supplied. Draft tools are not exposed to the LLM\nduring agent runs; call the activate endpoint to promote them.\n\nFor built-in tools that support multiple instances per agent (those whose\ncatalog entry has a `multi_instance_mode`), supply `name_prefix` to\nnamespace the LLM-facing tool names. Requires app scope.\n", + "operationId": "post_api_v1_agents__agent_agent_tools", + "parameters": [ + { + "description": "Agent ID (`agt_...`) to attach the tool to.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "async": true, + "builtin_tool_config": {}, + "builtin_tool_key": "string", + "config": "string", + "description": "An example description.", + "handler_type": "string", + "kind": "string", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "name_prefix": "string", + "parameters": {}, + "status": "string" + }, + "properties": { + "async": { + "description": "When `true`, the tool executes asynchronously and the agent does not block waiting for a result. Applies to `\"custom\"` tools.", + "example": true, + "type": "boolean" + }, + "builtin_tool_config": { + "description": "Configuration object for the built-in tool. Shape is defined by the catalog entry's `config_schema` for the chosen `builtin_tool_key`. Applies only to `\"builtin\"` tools.", + "example": {}, + "type": "object" + }, + "builtin_tool_key": { + "description": "Key identifying the built-in tool type to add (e.g. `\"knowledge_search\"`). Required when `kind` is `\"builtin\"`. Must match a key in the tool catalog.", + "example": "string", + "type": "string" + }, + "config": { + "description": "Config ID (`cfg_...`) referencing the script or workflow graph that implements the tool handler. Applies to `\"custom\"` tools.", + "example": "string", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the tool does. Shown to the LLM as context. Applies primarily to `\"custom\"` tools.", + "example": "An example description.", + "type": "string" + }, + "handler_type": { + "description": "Execution handler for the tool. One of `\"script\"` or `\"workflow_graph\"`. Applies to `\"custom\"` tools.", + "example": "string", + "type": "string" + }, + "kind": { + "description": "Tool kind. One of `\"builtin\"` or `\"custom\"`.", + "example": "string", + "type": "string" + }, + "lookup_key": { + "description": "Optional stable identifier you can use to look up this tool without its ID. Must be unique within the app. Useful for idempotent provisioning.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata to attach to the tool. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Display name for the tool. Required when `kind` is `\"custom\"`.", + "example": "Example Name", + "type": "string" + }, + "name_prefix": { + "description": "Per-instance namespace for built-in tools that support multiple instances per agent. Stamped onto LLM-facing tool names (e.g. `\"org\"` produces `\"org_knowledge_search\"`). Must match `^[a-z][a-z0-9_]*$` and be at most 24 characters. Required for `\"namespaced\"` multi-instance tools; omit for single-instance tools.", + "example": "string", + "type": "string" + }, + "parameters": { + "description": "JSON Schema object describing the tool's input parameters. Used by the LLM to construct valid tool calls. Applies to `\"custom\"` tools.", + "example": {}, + "type": "object" + }, + "status": { + "description": "Initial status of the tool. One of `\"draft\"` or `\"active\"`. Defaults to `\"draft\"` when omitted.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentTool" + } + } + }, + "description": "The newly created tool." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create an agent tool", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/agent_working_memory": { + "get": { + "description": "Returns a paginated list of working memory entries belonging to the specified\nagent. Entries are key-value pairs the agent stores for context between\ninteractions. Results are ordered by creation time descending (newest first)\nand can be filtered with a substring search against the key name.\n\nRequires an app-scoped API key. The authenticated caller must have access to\nthe app the agent belongs to. Returns 403 if the key is not app-scoped, and\n404 if the agent does not exist within the accessible scope.\n", + "operationId": "get_api_v1_agents__agent_agent_working_memory", + "parameters": [ + { + "description": "Agent ID (`agt_...`) whose working memory entries to retrieve.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Page number to retrieve, starting at 1. Defaults to 1.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of entries to return per page. Defaults to 25.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Substring filter applied to entry keys (case-insensitive). Omit to return all keys.", + "example": "string", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkingMemoryEntryListResponse" + } + } + }, + "description": "Paginated list of working memory entries for the agent." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + } + }, + "summary": "List working memory entries for an agent", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/agent_working_memory/{entry}": { + "delete": { + "description": "Permanently deletes a working memory entry from the agent. This action is\nirreversible. Expired entries can also be deleted — they are hidden from\nlist results but persist until overwritten or deleted.\n\nRequires an app-scoped API key. The authenticated caller must be able to\nmodify the agent that owns the entry. Returns 403 if the key is not\napp-scoped or the caller lacks modify access, and 404 if the agent or entry\ndoes not exist within the accessible scope.\n", + "operationId": "delete_api_v1_agents__agent_agent_working_memory__entry", + "parameters": [ + { + "description": "Agent ID (`agt_...`) that owns the working memory entry.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Working memory entry ID (`amm_...`) to delete.", + "example": "string", + "in": "path", + "name": "entry", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty body. Returns HTTP 204 on success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope or agent modify access required" + }, + "404": { + "description": "Agent or working memory entry not found" + } + }, + "summary": "Delete a working memory entry", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "patch": { + "description": "Updates the value and/or expiry of an existing working memory entry. Only\nthe fields you supply are changed; omitted fields retain their current\nvalues. The entry `key` cannot be changed after creation — delete the entry\nand let the agent (or a future create call) write a new one instead.\n\nPass `expires_at` as `null` to remove the expiry so the entry no longer\nexpires. Expired entries can still be updated; they stay hidden from list\nresults until their expiry is in the future again.\n\nRequires an app-scoped API key. The authenticated caller must be able to\nmodify the agent that owns the entry. Returns 403 if the key is not\napp-scoped or the caller lacks modify access, and 404 if the agent or entry\ndoes not exist within the accessible scope.\n", + "operationId": "patch_api_v1_agents__agent_agent_working_memory__entry", + "parameters": [ + { + "description": "Agent ID (`agt_...`) that owns the working memory entry.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Working memory entry ID (`amm_...`) to update.", + "example": "string", + "in": "path", + "name": "entry", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "value": "string" + }, + "properties": { + "expires_at": { + "description": "New expiry for the entry (ISO 8601). Pass `null` to remove the expiry so the entry never expires. Omit to keep the current expiry.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "value": { + "description": "Replacement string value to store under the entry's key. Maximum 65,536 characters.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkingMemoryEntry" + } + } + }, + "description": "The updated working memory entry." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope or agent modify access required" + }, + "404": { + "description": "Agent or working memory entry not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Update a working memory entry", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/export": { + "get": { + "description": "Reconstructs an AgentTemplate config from a deployed agent and all of its\nsub-resources (tools, routines, skills, installations). Returns the template\ndefinition together with every dependent config file (scripts, workflows, skills,\nschemas) and their raw content, producing a fully self-contained export bundle.\n\nUse this endpoint to snapshot an agent's current configuration for backup,\nmigration, or to seed a new Solution template. Pass `remove_identity: true` to\nstrip instance-specific fields (email, phone number) before export.\n\nThe authenticated caller must own the agent or hold sufficient permissions within\nits owning org or team. When called under a developer app scope, the caller must\nhold the app scope for the target app.\n", + "operationId": "get_api_v1_agents__agent_export", + "parameters": [ + { + "description": "ID (`agi_...`) or `lookup_key` of the agent to export.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "When `true`, strips instance-unique identity fields (`email`, `phone_number`) from the exported template so it can be reused as a generic blueprint.", + "example": true, + "in": "query", + "name": "remove_identity", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentExport" + } + } + }, + "description": "Export bundle containing the reconstructed AgentTemplate and all dependent config files with their raw content." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + } + }, + "summary": "Export an agent as an AgentTemplate", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/health": { + "get": { + "description": "Returns an aggregate health profile for the specified agent, including an overall\nstatus, a numeric health score, recent activity metrics, and a list of recommended\nremediation actions.\n\nThe health check is computed on demand at request time. The `checked_at` timestamp\nin the response reflects when the evaluation ran. Use this endpoint to surface\ndiagnostics about tool availability, model configuration, and runtime activity in\ndashboards or monitoring workflows.\n\nThe authenticated caller must own the agent or hold sufficient permissions within\nits owning org or team. When called under a developer app scope, the caller must\nhold the app scope for the target app.\n", + "operationId": "get_api_v1_agents__agent_health", + "parameters": [ + { + "description": "ID (`agi_...`) or `lookup_key` of the agent to evaluate.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentHealth" + } + } + }, + "description": "Aggregate health profile for the agent, including status, score, activity metrics, and recommended actions." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + } + }, + "summary": "Retrieve an agent's health profile", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/schedules": { + "get": { + "description": "Returns all schedules belonging to the specified agent in any status. Use the\n`status` parameter to narrow results to a single lifecycle state.\n\nRequires an app-scoped API key. The agent must belong to the app identified\nby the key.\n", + "operationId": "get_api_v1_agents__agent_schedules", + "parameters": [ + { + "description": "Agent ID (`agi_...`). The agent whose schedules you want to retrieve.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Filter results by schedule status. One of `\"active\"`, `\"paused\"`, `\"completed\"`, `\"cancelled\"`, or `\"expired\"`. Omit to return schedules in all statuses.", + "example": "string", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "A list of schedule objects for the agent.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "cron_expression": "0 9 * * 1", + "id": "asc_0aBcDeFgHiJkLmNoPqRsTu", + "instructions": "Send a daily summary of open support tickets to the team Slack channel.", + "last_run_at": "2024-01-01T00:00:00Z", + "max_runs": 10, + "metadata": { + "key": "value" + }, + "next_run_at": "2024-01-01T00:00:00Z", + "run_count": 1, + "schedule_type": "recurring", + "scheduled_at": "2024-01-01T00:00:00Z", + "status": "active", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "timezone": "America/New_York", + "updated_at": "2024-01-01T00:00:00Z" + } + ] + }, + "properties": { + "data": { + "description": "Array of agent schedule objects matching the query.", + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "cron_expression": "0 9 * * 1", + "id": "asc_0aBcDeFgHiJkLmNoPqRsTu", + "instructions": "Send a daily summary of open support tickets to the team Slack channel.", + "last_run_at": "2024-01-01T00:00:00Z", + "max_runs": 10, + "metadata": { + "key": "value" + }, + "next_run_at": "2024-01-01T00:00:00Z", + "run_count": 1, + "schedule_type": "recurring", + "scheduled_at": "2024-01-01T00:00:00Z", + "status": "active", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "timezone": "America/New_York", + "updated_at": "2024-01-01T00:00:00Z" + } + ], + "items": { + "description": "A scheduled task created by an agent. Supports one-time and recurring (cron-based) execution patterns.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "cron_expression": "0 9 * * 1", + "id": "asc_0aBcDeFgHiJkLmNoPqRsTu", + "instructions": "Send a daily summary of open support tickets to the team Slack channel.", + "last_run_at": "2024-01-01T00:00:00Z", + "max_runs": 10, + "metadata": { + "key": "value" + }, + "next_run_at": "2024-01-01T00:00:00Z", + "run_count": 1, + "schedule_type": "recurring", + "scheduled_at": "2024-01-01T00:00:00Z", + "status": "active", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "timezone": "America/New_York", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this schedule (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app": { + "description": "ID of the application the schedule belongs to (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the schedule was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "cron_expression": { + "description": "Standard cron expression defining the recurrence pattern (e.g. `\"0 9 * * 1\"`). Present only when `schedule_type` is `\"recurring\"`. `null` for one-time schedules.", + "example": "0 9 * * 1", + "type": "string" + }, + "id": { + "description": "Schedule ID (`asc_...`).", + "example": "asc_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "instructions": { + "description": "The task description the agent will execute when this schedule fires.", + "example": "Send a daily summary of open support tickets to the team Slack channel.", + "type": "string" + }, + "last_run_at": { + "description": "UTC datetime of the most recent successful execution. `null` if the schedule has never run.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "max_runs": { + "description": "Maximum number of times a recurring schedule may fire before automatically transitioning to `\"completed\"`. `null` means no limit.", + "example": 10, + "type": "integer" + }, + "metadata": { + "description": "Arbitrary key-value pairs attached to the schedule by the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "next_run_at": { + "description": "UTC datetime of the next planned execution. `null` if the schedule has completed, been cancelled, or has not yet been computed.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "run_count": { + "description": "Total number of times this schedule has fired.", + "example": 1, + "type": "integer" + }, + "schedule_type": { + "description": "Determines how the schedule repeats. `\"once\"` fires a single time at `scheduled_at` then transitions to `\"completed\"`. `\"recurring\"` fires on the `cron_expression` and reschedules automatically.", + "example": "recurring", + "type": "string" + }, + "scheduled_at": { + "description": "The exact UTC datetime at which a one-time schedule fires. Present only when `schedule_type` is `\"once\"`. `null` for recurring schedules.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "status": { + "description": "Current lifecycle status of the schedule. One of `\"active\"` (will fire as planned), `\"paused\"` (temporarily suspended), `\"completed\"` (has run its last execution), `\"cancelled\"` (manually stopped), or `\"expired\"` (past its valid window).", + "example": "active", + "type": "string" + }, + "thread": { + "description": "Thread ID (`thr_...`) this schedule is bound to. When set, the scheduled task is delivered into the thread rather than creating a new session. `null` for session-based schedules.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "timezone": { + "description": "IANA timezone name used to interpret the cron expression or `scheduled_at` (e.g. `\"America/New_York\"`). Defaults to `\"Etc/UTC\"`.", + "example": "America/New_York", + "type": "string" + }, + "updated_at": { + "description": "When the schedule was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Invalid status value" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + } + }, + "summary": "List schedules for an agent", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/schedules/{schedule}": { + "get": { + "description": "Returns a single schedule belonging to the specified agent. Use this endpoint\nto fetch the current state, next run time, and configuration of an individual\nschedule.\n\nRequires an app-scoped API key. Both the agent and the schedule must belong\nto the app identified by the key. Returns 404 if the schedule does not exist\nor belongs to a different agent.\n", + "operationId": "get_api_v1_agents__agent_schedules__schedule", + "parameters": [ + { + "description": "Agent ID (`agi_...`). The agent that owns the schedule.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Schedule ID (`asc_...`). The schedule to retrieve.", + "example": "string", + "in": "path", + "name": "schedule", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentSchedule" + } + } + }, + "description": "The requested agent schedule." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Schedule not found" + } + }, + "summary": "Retrieve a schedule", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/search": { + "post": { + "description": "Performs a semantic search over an agent's knowledge base and returns a ranked,\n`kind`-discriminated list of matching items.\n\nTwo item kinds may appear in `data`:\n\n- `\"chunk\"` — chunk-level results from the agent's context store. Present for all agents.\n- `\"document\"` — document-level results. Present only when the agent has an active\n `archastro/knowledge` installation.\n\nResults from both kinds are scored with Reciprocal Rank Fusion (RRF), normalized to\nbe comparable across kinds, then merged into a single ranked list. On a relevance tie,\nchunks appear before documents. The total number of results is capped at `max_results`\nacross both kinds.\n\nUse `mode` to choose the retrieval strategy: `\"hybrid\"` (default) combines vector and\nfull-text search; `\"vector\"` and `\"fulltext\"` select each strategy independently.\n", + "operationId": "post_api_v1_agents__agent_search", + "parameters": [ + { + "description": "ID (`agi_...`) or `lookup_key` of the agent whose knowledge base to search.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "max_results": 1, + "min_similarity": 1.0, + "mode": "string", + "query": "string", + "recency_days": 1, + "source_types": [ + "string" + ] + }, + "properties": { + "max_results": { + "description": "Maximum total results to return across all kinds. Chunks and documents are ranked together and the list is capped at this value. Defaults to `20`; maximum is `100`.", + "example": 1, + "type": "integer" + }, + "min_similarity": { + "description": "Cosine-similarity floor for the vector leg, 0.0-1.0, applied to both chunk and document results. Candidates below it are discarded before ranking, so a high value trades recall for precision. Pass `0.0` to disable the floor when a missed match costs more than a weak one — note that with no floor every query returns results, so an empty response can no longer be read as \"no match\". Omit to use the default.", + "example": 1.0, + "type": "number" + }, + "mode": { + "description": "Retrieval strategy. One of `\"hybrid\"` (default), `\"vector\"`, or `\"fulltext\"`.", + "example": "string", + "type": "string" + }, + "query": { + "description": "Natural-language search query used to retrieve relevant knowledge items.", + "example": "string", + "type": "string" + }, + "recency_days": { + "description": "When set, restricts results to items indexed within the last N days.", + "example": 1, + "type": "integer" + }, + "source_types": { + "description": "Array of source-type slugs used to filter chunk results, e.g. `[\"web\", \"file\"]`. Omit to include all source types.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "query" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Knowledge search results for the specified agent.", + "example": { + "data": [] + }, + "properties": { + "data": { + "description": "Ranked list of matching knowledge items. Each item is a `kind`-discriminated union — either `\"chunk\"` (always present) or `\"document\"` (present only when the agent has an active `archastro/knowledge` installation). Sorted by relevance descending; capped at `max_results` total across both kinds.", + "example": [], + "items": { + "description": "A discriminated union representing a single result from a knowledge search. The `kind` field identifies the variant: `\"chunk\"` for a chunk-level result (see `KnowledgeSearchResult`) or `\"document\"` for a document-level result (see `DocumentSearchResult`).\n", + "discriminator": { + "propertyName": "kind" + }, + "oneOf": [ + { + "description": "A single chunk returned by a knowledge search query. Represents an indexed content item matched against the search terms.", + "example": { + "content": "ArchAstro connects your agents to external knowledge sources for real-time context retrieval.", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "id": "cim_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "chunk", + "metadata": { + "key": "value" + }, + "raw_content": {}, + "type": "gmail" + }, + "properties": { + "content": { + "description": "Normalized plain-text content of the matched chunk.", + "example": "ArchAstro connects your agents to external knowledge sources for real-time context retrieval.", + "type": "string" + }, + "content_type": { + "description": "MIME type of the content, e.g. `\"text/plain\"` or `\"text/html\"`.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this item was indexed into the knowledge base (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Context item ID (`cim_...`).", + "example": "cim_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "default": "chunk", + "description": "Result variant discriminator. Always `\"chunk\"` for this object type.", + "enum": [ + "chunk" + ], + "example": "chunk", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this item by the source connector.", + "example": { + "key": "value" + }, + "type": "object" + }, + "raw_content": { + "description": "Raw content payload as stored by the source connector, before normalization.", + "example": {}, + "type": "object" + }, + "type": { + "description": "Type identifier of the parent knowledge source (e.g. `\"gmail\"`, `\"github_activity\"`). Returns `\"unknown\"` when the source association is not loaded.", + "example": "gmail", + "type": "string" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + }, + { + "description": "A single document-level result returned by a knowledge search query. Includes a short preview snippet and content statistics alongside the document's metadata.", + "example": { + "id": "cdo_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "document", + "metadata": { + "key": "value" + }, + "snippet": "This document describes the onboarding workflow for new users, including account setup, initial configuration steps, and a guided tour of the main features…", + "title": "Example Title", + "total_lines": 42, + "total_size": 1024 + }, + "properties": { + "id": { + "description": "Document ID (`cdo_...`).", + "example": "cdo_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "default": "document", + "description": "Result variant discriminator. Always `\"document\"` for this schema; use this field to distinguish document results from other `KnowledgeResult` variants.", + "enum": [ + "document" + ], + "example": "document", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the document. `null` if no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "snippet": { + "description": "Leading 300-character preview of the document's text content, trimmed of surrounding whitespace. Truncated with an ellipsis when the full content exceeds the limit.", + "example": "This document describes the onboarding workflow for new users, including account setup, initial configuration steps, and a guided tour of the main features…", + "type": "string" + }, + "title": { + "description": "Title of the document as stored in the knowledge base. `null` if the document has no title.", + "example": "Example Title", + "type": "string" + }, + "total_lines": { + "description": "Total number of lines in the document's text content. `0` for empty documents.", + "example": 42, + "type": "integer" + }, + "total_size": { + "description": "Total byte size of the document's text content encoded as UTF-8. `0` for empty documents.", + "example": 1024, + "type": "integer" + } + }, + "required": [ + "kind", + "id" + ], + "type": "object" + } + ] + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Search an agent's knowledge base", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/threads": { + "post": { + "description": "Creates a new thread owned by the specified agent. The thread is scoped to the\nagent's identity and is immediately available for messaging.\n\nThe authenticated caller must have access to the agent's parent app. If your\nAPI key is scoped to a specific app, pass that app's ID via the `app` parameter.\nAttempting to create a thread for an agent you cannot access returns 404.\n\nBy default the platform may send an automatic welcome message into the new\nthread. Pass `skip_welcome_message: true` to suppress this behavior.\n", + "operationId": "post_api_v1_agents__agent_threads", + "parameters": [ + { + "description": "Agent ID (`agt_...`). The thread will be owned by this agent.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "skip_welcome_message": true, + "thread": { + "create_legacy_agent": true, + "description": "An example description.", + "is_unlisted": true, + "key": "string", + "members": [ + { + "id": "string", + "type": "user" + } + ], + "metadata": { + "key": "value" + }, + "muted": true, + "org_id": "string", + "profile_picture": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "title": "Example Title", + "visibility": "team" + } + }, + "properties": { + "skip_welcome_message": { + "description": "When `true`, suppresses the automatic welcome message that the platform sends when a new thread is created. Defaults to `false`.", + "example": true, + "type": "boolean" + }, + "thread": { + "description": "Attributes for the new thread. See ThreadCreateParams for available fields.", + "example": { + "create_legacy_agent": true, + "description": "An example description.", + "is_unlisted": true, + "key": "string", + "members": [ + { + "id": "string", + "type": "user" + } + ], + "metadata": { + "key": "value" + }, + "muted": true, + "org_id": "string", + "profile_picture": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "title": "Example Title", + "visibility": "team" + }, + "properties": { + "create_legacy_agent": { + "description": "When `true`, provisions a legacy chat agent alongside the thread. Only needed for integrations that depend on the pre-v2 agent model.", + "example": true, + "type": "boolean" + }, + "description": { + "description": "Optional longer description of the thread's purpose. `null` if not provided.", + "example": "An example description.", + "type": "string" + }, + "is_unlisted": { + "description": "When `true`, the thread is hidden from the default thread list and accessible only by direct link or ID.", + "example": true, + "type": "boolean" + }, + "key": { + "description": "Client-assigned unique key for idempotent creation or later lookup. Must be unique within the owning organization.", + "example": "string", + "type": "string" + }, + "members": { + "description": "Users and agents to add atomically when the thread is created. Each target must pass the same authorization rules as a post-creation member add. Slack mirror threads reject non-empty caller-supplied rosters because their membership is sync-owned.", + "example": [ + { + "id": "string", + "type": "user" + } + ], + "items": { + "description": "A user or agent to add atomically when the thread is created.", + "example": { + "id": "string", + "type": "user" + }, + "properties": { + "id": { + "description": "Public user (`usr_...`) or agent (`agt_...`) ID matching `type`.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Member kind. Use `user` for a user ID or `agent` for an agent ID.", + "enum": [ + "user", + "agent" + ], + "example": "user", + "type": "string" + } + }, + "required": [ + "type", + "id" + ], + "type": "object" + }, + "type": "array" + }, + "metadata": { + "description": "Arbitrary key-value pairs stored alongside the thread. Values must be strings or numbers.", + "example": { + "key": "value" + }, + "type": "object" + }, + "muted": { + "description": "When `true`, push and in-app notifications for this thread are suppressed for the creating user.", + "example": true, + "type": "boolean" + }, + "org_id": { + "description": "ID of the organization to create the thread under. Defaults to the authenticated user's primary organization when omitted.", + "example": "string", + "type": "string" + }, + "profile_picture": { + "description": "Optional profile image for the thread, provided as a base64-encoded payload.", + "example": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "properties": { + "data": { + "description": "Base64-encoded image bytes.", + "example": "string", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded image, used for display and content-type inference.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`.", + "example": "application/json", + "type": "string" + } + }, + "type": "object" + }, + "settings": { + "description": "Configuration overrides for the thread, such as AI model selection and context window settings.", + "example": { + "agent_enabled": true + }, + "properties": { + "agent_enabled": { + "description": "Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured.", + "example": true, + "type": "boolean" + } + }, + "type": "object" + }, + "slug": { + "description": "Optional URL-safe identifier. Derived from the title when omitted and unique within the thread owner.", + "example": "example-slug", + "type": "string" + }, + "title": { + "description": "Display name for the thread. `null` if omitted, which causes the thread to be untitled.", + "example": "Example Title", + "type": "string" + }, + "visibility": { + "description": "Thread visibility. A team-owned thread with members must explicitly use `restricted` or `private`. User- and agent-owned threads with members default to `private` and reject every other value.", + "enum": [ + "team", + "restricted", + "private" + ], + "example": "team", + "type": "string" + } + }, + "type": "object" + } + }, + "required": [ + "thread" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Thread" + } + } + }, + "description": "The newly created thread." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create a thread for an agent", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/upgrade": { + "post": { + "description": "Upgrades an existing agent by reconciling it against an AgentTemplate from a\nSolution. Supports two modes:\n\n- `\"reapply\"` (default) — re-applies the agent's currently tracked template,\n picking up any changes the template author has made since the last apply.\n- `\"replace\"` — moves the agent to a different template. `template` is required\n in this mode.\n\nSet `dry_run: true` to compute and return the full upgrade diff (adds, updates,\nremoves, noops) without writing any changes. The response includes a\n`review_fingerprint` you can pass back via `expected_review_fingerprint` on the\nlive apply to guard against the diff changing between review and execution.\n\nSafe overrides (`name`, `description`, `email`, `phone_number`, `metadata`,\n`identity`, `originator`, `model`) let you pin instance-specific values that\nshould not be overwritten by the template during the upgrade.\n\nThe authenticated caller must own the agent or hold write permissions within its\nowning org or team. When called under a developer app scope, the caller must hold\nthe app scope for the target app.\n", + "operationId": "post_api_v1_agents__agent_upgrade", + "parameters": [ + { + "description": "ID (`agi_...`) or `lookup_key` of the agent to upgrade.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "description": "An example description.", + "dry_run": true, + "email": "user@example.com", + "expected_review_fingerprint": "string", + "identity": "string", + "metadata": { + "key": "value" + }, + "mode": "reapply", + "model": "string", + "name": "Example Name", + "originator": "string", + "phone_number": "+15555550123", + "template": "string" + }, + "properties": { + "description": { + "description": "Instance-specific description override. Pins this value so the template upgrade does not overwrite it.", + "example": "An example description.", + "type": "string" + }, + "dry_run": { + "description": "When `true`, computes and returns the full upgrade diff without persisting any changes. Use with `expected_review_fingerprint` to guard the live apply.", + "example": true, + "type": "boolean" + }, + "email": { + "description": "Instance-specific email address override. Pins this value so the template upgrade does not overwrite it.", + "example": "user@example.com", + "type": "string" + }, + "expected_review_fingerprint": { + "description": "Stale-review guard. Pass the `review_fingerprint` returned by a prior `dry_run` response to ensure the diff has not changed between review and live apply. Returns an error if the fingerprint no longer matches.", + "example": "string", + "type": "string" + }, + "identity": { + "description": "Instance-specific identity system-prompt override. Pins this value so the template upgrade does not overwrite it.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Instance-specific metadata override. Pins this value so the template upgrade does not overwrite it.", + "example": { + "key": "value" + }, + "type": "object" + }, + "mode": { + "description": "Upgrade mode. `\"reapply\"` (default) refreshes the agent's tracked template; `\"replace\"` moves the agent to a different template (requires `template`).", + "enum": [ + "reapply", + "replace" + ], + "example": "reapply", + "type": "string" + }, + "model": { + "description": "Instance-specific default model override. Pins this value so the template upgrade does not overwrite it. Pass an empty string to clear the model.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Instance-specific name override. Pins this value so the template upgrade does not overwrite it.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Instance-specific originator label override. Pins this value so the template upgrade does not overwrite it.", + "example": "string", + "type": "string" + }, + "phone_number": { + "description": "Instance-specific phone number override in E.164 format. Pins this value so the template upgrade does not overwrite it.", + "example": "+15555550123", + "type": "string" + }, + "template": { + "description": "ID (`cfg_...`) or `lookup_key` of the target AgentTemplate config. Optional in `\"reapply\"` mode; required in `\"replace\"` mode.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentUpgradeResponse" + } + } + }, + "description": "The upgrade outcome, including the updated agent, the source Solution and template summaries, and the full diff (`upgrade_result`) with status, dry-run flag, aggregate counts, and a per-resource change list. When `dry_run` is `true`, `agent` is `null` and no changes are persisted." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Agent not found; Template not found; This agent's template is no longer part of its Solution. The Solution may have been changed or re-synced since this agent was installed." + }, + "409": { + "description": "Agent template changed since review; prepare the diff again." + }, + "422": { + "description": "Agent has no tracked template; Template has no parent Solution; Config is not an agent template; Validation failed" + } + }, + "summary": "Upgrade an agent from an AgentTemplate", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/work_items": { + "get": { + "description": "Lists queued, claimed, and running external work yielded by durable workflows.\nThe top-level collection includes work for every agent the viewer can execute;\nthe agent-nested collection limits results to that agent. This discovery\nresponse never includes lease tokens. Use the agent claim endpoint to acquire\nnew work or resume a saved lease.\n", + "operationId": "get_api_v1_agents__agent_work_items", + "parameters": [ + { + "description": "Agent ID or lookup key injected by the nested route.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Optional durable execution ID filter.", + "example": "string", + "in": "query", + "name": "execution", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum work items per page. Defaults to 50; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor for the next page of older queued work.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkflowWorkItemList" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Invalid cursor" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "List active workflow work available to the viewer", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/agents/{agent}/work_items/claim": { + "post": { + "description": "Atomically claims the oldest queued or lease-expired item. To resume after a\nharness restart, pass both the saved `work_item` and the same `lease_owner`;\nthe server refreshes that active lease without incrementing its attempt.\nReturns `data: null` when no eligible item exists, including when another\nlease owns the explicitly requested item.\n", + "operationId": "post_api_v1_agents__agent_work_items_claim", + "parameters": [ + { + "description": "Agent ID or lookup key.", + "example": "string", + "in": "path", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "execution": "string", + "lease_owner": "string", + "lease_seconds": 1, + "work_item": "string" + }, + "properties": { + "execution": { + "description": "Optional durable execution ID filter.", + "example": "string", + "type": "string" + }, + "lease_owner": { + "description": "Caller-generated random UUID lease token.", + "example": "string", + "type": "string" + }, + "lease_seconds": { + "description": "Lease duration from 15 through 3600 seconds. Defaults to 300.", + "example": 1, + "type": "integer" + }, + "work_item": { + "description": "Saved work item ID to resume or reclaim.", + "example": "string", + "type": "string" + } + }, + "required": [ + "lease_owner" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkflowWorkItemClaim" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "Invalid parameters; Validation failed" + } + }, + "summary": "Claim or resume workflow work for an agent", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/ai/chat/completions": { + "post": { + "description": "Sends a list of messages to the configured AI provider and returns a single\ncompletion. Use this endpoint when you want direct, low-level access to the\nunderlying model without any workflow or agent orchestration.\n\nThe authenticated app must have the `llm_calls` entitlement enabled on its\nplan. Requests that exceed the plan quota are rejected with `402`. Token\nusage is recorded against the authenticated app and organization.\n\nSupply `tools` and `tool_choice` to enable OpenAI-compatible function\ncalling. Use `server_tools` to activate platform-managed tools such as\nsearch that run on the server side before the response is returned.\n", + "operationId": "post_api_v1_ai_chat_completions", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "context": {}, + "messages": [ + { + "content": "How can I help you today?", + "content_parts": [ + {} + ], + "resume_token": "string", + "role": "user", + "tool_calls": [ + { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + } + ], + "tool_results": [ + { + "content": "string", + "id": "string", + "name": "Example Name" + } + ] + } + ], + "opts": { + "max_tokens": 1, + "model": "string", + "server_tools": [ + {} + ], + "structured_output": {}, + "temperature": 1.0, + "tool_choice": "string", + "tools": [ + { + "function": { + "description": "An example description.", + "name": "Example Name", + "parameters": {} + }, + "type": "function" + } + ] + }, + "session_id": "string" + }, + "properties": { + "context": { + "description": "Key-value map used to resolve template variables in message content. Omit if messages contain no templates.", + "example": {}, + "type": "object" + }, + "messages": { + "description": "Ordered list of conversation messages to send to the model.", + "example": [ + { + "content": "How can I help you today?", + "content_parts": [ + {} + ], + "resume_token": "string", + "role": "user", + "tool_calls": [ + { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + } + ], + "tool_results": [ + { + "content": "string", + "id": "string", + "name": "Example Name" + } + ] + } + ], + "items": { + "description": "A single message in an AI conversation, following the OpenAI-compatible chat format. Used in both request inputs and completion responses.", + "example": { + "content": "How can I help you today?", + "content_parts": [ + {} + ], + "resume_token": "string", + "role": "user", + "tool_calls": [ + { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + } + ], + "tool_results": [ + { + "content": "string", + "id": "string", + "name": "Example Name" + } + ] + }, + "properties": { + "content": { + "description": "Plain-text content of the message. Present for `system`, `user`, and `assistant` messages. `null` when the message body is expressed through `content_parts` or `tool_calls`.", + "example": "How can I help you today?", + "type": "string" + }, + "content_parts": { + "description": "Multimodal content parts for the message, used when the body includes images or mixed media. Each part is a map with a `type` key (`\"text\"`, `\"image_url\"`, or `\"image_data\"`). `null` when `content` is set.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "resume_token": { + "description": "Opaque token that can be passed on a subsequent request to resume this conversation from the current state. `null` when the provider does not support conversation resumption.", + "example": "string", + "type": "string" + }, + "role": { + "description": "The speaker role for this message. One of `\"system\"`, `\"user\"`, `\"assistant\"`, or `\"tool\"`.", + "example": "user", + "type": "string" + }, + "structured_output": { + "description": "Parsed structured data returned by the model when a JSON schema or structured-output mode was requested. Shape varies by the schema supplied at call time. `null` when structured output was not requested." + }, + "tool_calls": { + "description": "Tool calls requested by the model in an `assistant` message. Present only on assistant messages that invoke one or more tools. `null` on all other message roles.", + "example": [ + { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + } + ], + "items": { + "description": "A tool (function) call emitted by the assistant within an AI message. Mirrors the OpenAI tool-call object format.", + "example": { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + }, + "properties": { + "arguments": { + "description": "Arguments the model wants to pass to the tool, as a key-value map. Deserialize and validate these against the tool's input schema before executing.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Unique identifier for this tool call, assigned by the model. Use this value as `id` when submitting the corresponding tool result.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Name of the tool or function the model wants to invoke, e.g. `\"web_search\"` or `\"run_code\"`.", + "example": "Example Name", + "type": "string" + }, + "thought_signature": { + "description": "Opaque signature representing the model's internal reasoning that led to this tool call. `null` when the provider does not expose chain-of-thought data.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "name", + "arguments" + ], + "type": "object" + }, + "type": "array" + }, + "tool_results": { + "description": "Tool execution results provided in a `tool` message. Each entry corresponds to a prior tool call by its `id`. `null` on all other message roles.", + "example": [ + { + "content": "string", + "id": "string", + "name": "Example Name" + } + ], + "items": { + "description": "The result of executing a tool call, submitted back to the model as a tool-role message. Mirrors the OpenAI tool-result object format.", + "example": { + "content": "string", + "id": "string", + "name": "Example Name" + }, + "properties": { + "content": { + "description": "Plain-text output produced by the tool execution. `null` when the result is expressed entirely through `resolution`.", + "example": "string", + "type": "string" + }, + "id": { + "description": "ID of the tool call this result satisfies. Must match the `id` from the corresponding `AIToolCall`.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Name of the tool or function that was executed, e.g. `\"web_search\"`. Must match the `name` from the corresponding `AIToolCall`.", + "example": "Example Name", + "type": "string" + }, + "resolution": { + "description": "Structured result data from the tool execution. Shape varies by tool. `null` when the result is expressed as plain text in `content`." + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "role" + ], + "type": "object" + }, + "type": "array" + }, + "opts": { + "description": "Model and sampling configuration for this request.", + "example": { + "max_tokens": 1, + "model": "string", + "server_tools": [ + {} + ], + "structured_output": {}, + "temperature": 1.0, + "tool_choice": "string", + "tools": [ + { + "function": { + "description": "An example description.", + "name": "Example Name", + "parameters": {} + }, + "type": "function" + } + ] + }, + "properties": { + "max_tokens": { + "description": "Maximum number of tokens the model may generate in the completion. Omit to use the model's default limit.", + "example": 1, + "type": "integer" + }, + "model": { + "description": "Model identifier to use for the completion, e.g. `\"gpt-4o\"` or `\"claude-3-7-sonnet-latest\"`.", + "example": "string", + "type": "string" + }, + "server_tools": { + "description": "Server-managed tool declarations executed before the response is returned. Each entry must include a `type` key; currently only `\"search\"` is supported.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "structured_output": { + "description": "Native structured-output configuration. Include a `schema` JSON Schema object and optional `name` and `strict` fields.", + "example": {}, + "type": "object" + }, + "temperature": { + "description": "Sampling temperature between `0.0` and `2.0`. Higher values produce more random output. Omit to use the model's default.", + "example": 1.0, + "type": "number" + }, + "tool_choice": { + "description": "Controls how the model selects tools. One of `\"auto\"`, `\"required\"`, or `\"none\"`. Omit to let the model decide.", + "example": "string", + "type": "string" + }, + "tools": { + "description": "OpenAI-compatible tool definitions available to the model. Omit when not using function calling.", + "example": [ + { + "function": { + "description": "An example description.", + "name": "Example Name", + "parameters": {} + }, + "type": "function" + } + ], + "items": { + "description": "An AI tool definition passed to a model, following the OpenAI tool-calling schema.", + "example": { + "function": { + "description": "An example description.", + "name": "Example Name", + "parameters": {} + }, + "type": "function" + }, + "properties": { + "function": { + "description": "Callable function this tool exposes, including its name, description, and parameter schema.", + "example": { + "description": "An example description.", + "name": "Example Name", + "parameters": {} + }, + "properties": { + "description": { + "description": "Human-readable description of what the function does. The model uses this to decide when to call the function. `null` if not provided.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "Unique name of the function that the model can invoke, e.g. `\"get_weather\"`.", + "example": "Example Name", + "type": "string" + }, + "parameters": { + "description": "JSON Schema object describing the function's accepted parameters. Must be a valid JSON Schema of type `\"object\"`.", + "example": {}, + "type": "object" + } + }, + "required": [ + "name", + "parameters" + ], + "type": "object" + }, + "type": { + "description": "The tool type. Currently always `\"function\"`.", + "example": "function", + "type": "string" + } + }, + "required": [ + "type", + "function" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "model" + ], + "type": "object" + }, + "session_id": { + "description": "Optional UUID grouping this and other completions under one session in the Developers dashboard. Pass the same value across requests to link them; omit to auto-generate a per-request session.", + "example": "string", + "type": "string" + } + }, + "required": [ + "messages", + "opts" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AICompletionResult" + } + } + }, + "description": "The completed AI response, including the generated message, finish reason, and token usage." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "402": { + "description": "Payment required — plan does not allow this feature" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create a chat completion", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/ai/chat/completions/stream": { + "post": { + "description": "Streams a chat completion over Server-Sent Events. Emits `thinking_delta` for\nsupported reasoning models, `message_delta`, `message_complete`,\n`tool_call_*`, `tool_result`, and a terminal `done` (or `error`) event. Same\nrequest shape as the non-streaming completion endpoint; the app must have the\n`llm_calls` entitlement.\n", + "operationId": "post_api_v1_ai_chat_completions_stream", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "context": {}, + "messages": [ + { + "content": "How can I help you today?", + "content_parts": [ + {} + ], + "resume_token": "string", + "role": "user", + "tool_calls": [ + { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + } + ], + "tool_results": [ + { + "content": "string", + "id": "string", + "name": "Example Name" + } + ] + } + ], + "opts": { + "max_tokens": 1, + "model": "string", + "server_tools": [ + {} + ], + "temperature": 1.0, + "tool_choice": "string", + "tools": [ + { + "function": { + "description": "An example description.", + "name": "Example Name", + "parameters": {} + }, + "type": "function" + } + ] + }, + "session_id": "string" + }, + "properties": { + "context": { + "description": "Key-value map used to resolve template variables in message content. Omit if messages contain no templates.", + "example": {}, + "type": "object" + }, + "messages": { + "description": "Ordered list of conversation messages to send to the model.", + "example": [ + { + "content": "How can I help you today?", + "content_parts": [ + {} + ], + "resume_token": "string", + "role": "user", + "tool_calls": [ + { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + } + ], + "tool_results": [ + { + "content": "string", + "id": "string", + "name": "Example Name" + } + ] + } + ], + "items": { + "description": "A single message in an AI conversation, following the OpenAI-compatible chat format. Used in both request inputs and completion responses.", + "example": { + "content": "How can I help you today?", + "content_parts": [ + {} + ], + "resume_token": "string", + "role": "user", + "tool_calls": [ + { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + } + ], + "tool_results": [ + { + "content": "string", + "id": "string", + "name": "Example Name" + } + ] + }, + "properties": { + "content": { + "description": "Plain-text content of the message. Present for `system`, `user`, and `assistant` messages. `null` when the message body is expressed through `content_parts` or `tool_calls`.", + "example": "How can I help you today?", + "type": "string" + }, + "content_parts": { + "description": "Multimodal content parts for the message, used when the body includes images or mixed media. Each part is a map with a `type` key (`\"text\"`, `\"image_url\"`, or `\"image_data\"`). `null` when `content` is set.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "resume_token": { + "description": "Opaque token that can be passed on a subsequent request to resume this conversation from the current state. `null` when the provider does not support conversation resumption.", + "example": "string", + "type": "string" + }, + "role": { + "description": "The speaker role for this message. One of `\"system\"`, `\"user\"`, `\"assistant\"`, or `\"tool\"`.", + "example": "user", + "type": "string" + }, + "structured_output": { + "description": "Parsed structured data returned by the model when a JSON schema or structured-output mode was requested. Shape varies by the schema supplied at call time. `null` when structured output was not requested." + }, + "tool_calls": { + "description": "Tool calls requested by the model in an `assistant` message. Present only on assistant messages that invoke one or more tools. `null` on all other message roles.", + "example": [ + { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + } + ], + "items": { + "description": "A tool (function) call emitted by the assistant within an AI message. Mirrors the OpenAI tool-call object format.", + "example": { + "arguments": {}, + "id": "string", + "name": "Example Name", + "thought_signature": "string" + }, + "properties": { + "arguments": { + "description": "Arguments the model wants to pass to the tool, as a key-value map. Deserialize and validate these against the tool's input schema before executing.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Unique identifier for this tool call, assigned by the model. Use this value as `id` when submitting the corresponding tool result.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Name of the tool or function the model wants to invoke, e.g. `\"web_search\"` or `\"run_code\"`.", + "example": "Example Name", + "type": "string" + }, + "thought_signature": { + "description": "Opaque signature representing the model's internal reasoning that led to this tool call. `null` when the provider does not expose chain-of-thought data.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "name", + "arguments" + ], + "type": "object" + }, + "type": "array" + }, + "tool_results": { + "description": "Tool execution results provided in a `tool` message. Each entry corresponds to a prior tool call by its `id`. `null` on all other message roles.", + "example": [ + { + "content": "string", + "id": "string", + "name": "Example Name" + } + ], + "items": { + "description": "The result of executing a tool call, submitted back to the model as a tool-role message. Mirrors the OpenAI tool-result object format.", + "example": { + "content": "string", + "id": "string", + "name": "Example Name" + }, + "properties": { + "content": { + "description": "Plain-text output produced by the tool execution. `null` when the result is expressed entirely through `resolution`.", + "example": "string", + "type": "string" + }, + "id": { + "description": "ID of the tool call this result satisfies. Must match the `id` from the corresponding `AIToolCall`.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Name of the tool or function that was executed, e.g. `\"web_search\"`. Must match the `name` from the corresponding `AIToolCall`.", + "example": "Example Name", + "type": "string" + }, + "resolution": { + "description": "Structured result data from the tool execution. Shape varies by tool. `null` when the result is expressed as plain text in `content`." + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "role" + ], + "type": "object" + }, + "type": "array" + }, + "opts": { + "description": "Model and sampling configuration for this request.", + "example": { + "max_tokens": 1, + "model": "string", + "server_tools": [ + {} + ], + "temperature": 1.0, + "tool_choice": "string", + "tools": [ + { + "function": { + "description": "An example description.", + "name": "Example Name", + "parameters": {} + }, + "type": "function" + } + ] + }, + "properties": { + "max_tokens": { + "description": "Maximum number of tokens the model may generate. Omit for the model default.", + "example": 1, + "type": "integer" + }, + "model": { + "description": "Model identifier, e.g. `\"gpt-4o\"` or `\"claude-3-7-sonnet-latest\"`.", + "example": "string", + "type": "string" + }, + "server_tools": { + "description": "Server-managed tool declarations executed before the response. Each entry must include a `type` key; currently only `\"search\"` is supported.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "temperature": { + "description": "Sampling temperature between `0.0` and `2.0`. Higher values produce more random output. Omit for the model default.", + "example": 1.0, + "type": "number" + }, + "tool_choice": { + "description": "Controls tool selection. One of `\"auto\"`, `\"required\"`, or `\"none\"`. Omit to let the model decide.", + "example": "string", + "type": "string" + }, + "tools": { + "description": "OpenAI-compatible tool definitions available to the model. Omit when not using function calling.", + "example": [ + { + "function": { + "description": "An example description.", + "name": "Example Name", + "parameters": {} + }, + "type": "function" + } + ], + "items": { + "description": "An AI tool definition passed to a model, following the OpenAI tool-calling schema.", + "example": { + "function": { + "description": "An example description.", + "name": "Example Name", + "parameters": {} + }, + "type": "function" + }, + "properties": { + "function": { + "description": "Callable function this tool exposes, including its name, description, and parameter schema.", + "example": { + "description": "An example description.", + "name": "Example Name", + "parameters": {} + }, + "properties": { + "description": { + "description": "Human-readable description of what the function does. The model uses this to decide when to call the function. `null` if not provided.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "Unique name of the function that the model can invoke, e.g. `\"get_weather\"`.", + "example": "Example Name", + "type": "string" + }, + "parameters": { + "description": "JSON Schema object describing the function's accepted parameters. Must be a valid JSON Schema of type `\"object\"`.", + "example": {}, + "type": "object" + } + }, + "required": [ + "name", + "parameters" + ], + "type": "object" + }, + "type": { + "description": "The tool type. Currently always `\"function\"`.", + "example": "function", + "type": "string" + } + }, + "required": [ + "type", + "function" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "model" + ], + "type": "object" + }, + "session_id": { + "description": "Optional UUID grouping this and other completions under one session in the Developers dashboard. Pass the same value across requests to link them; omit to auto-generate a per-request session.", + "example": "string", + "type": "string" + } + }, + "required": [ + "messages", + "opts" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "text/event-stream": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/AIChatStreamMessageDelta" + }, + { + "$ref": "#/components/schemas/AIChatStreamThinkingDelta" + }, + { + "$ref": "#/components/schemas/AIChatStreamMessageComplete" + }, + { + "$ref": "#/components/schemas/AIChatStreamToolCallDelta" + }, + { + "$ref": "#/components/schemas/AIChatStreamToolResult" + }, + { + "$ref": "#/components/schemas/AIChatStreamDone" + }, + { + "$ref": "#/components/schemas/AIChatStreamError" + } + ] + } + } + }, + "description": "Server-Sent Events stream" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "402": { + "description": "Payment required — plan does not allow this feature" + } + }, + "summary": "Stream a chat completion", + "x-auth": [ + "publishable_key", + "bearer" + ], + "x-sdk-streaming": { + "events": { + "done": { + "$ref": "#/components/schemas/AIChatStreamDone" + }, + "error": { + "$ref": "#/components/schemas/AIChatStreamError" + }, + "message_complete": { + "$ref": "#/components/schemas/AIChatStreamMessageComplete" + }, + "message_delta": { + "$ref": "#/components/schemas/AIChatStreamMessageDelta" + }, + "thinking_delta": { + "$ref": "#/components/schemas/AIChatStreamThinkingDelta" + }, + "tool_call_delta": { + "$ref": "#/components/schemas/AIChatStreamToolCallDelta" + }, + "tool_result": { + "$ref": "#/components/schemas/AIChatStreamToolResult" + } + }, + "type": "sse" + } + } + }, + "/api/v1/ai/chat/models": { + "get": { + "description": "Returns the set of AI models that can be used with the chat completion and\nworkflow endpoints. The list reflects models currently enabled for the\nplatform and includes each model's identifier and whether it is the default.\n\nUse the `model` field from any entry in `data` as the value for\n`opts.model` when calling the completions or workflows endpoint.\n", + "operationId": "get_api_v1_ai_chat_models", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "The set of AI models available for chat completions.", + "example": { + "data": [ + { + "capabilities": [ + "image" + ], + "context_window": 200000, + "default": true, + "id": "claude-sonnet-4-6", + "input_media_formats": [ + "string" + ], + "name": "Example Name", + "output_media_formats": [ + "string" + ] + } + ] + }, + "properties": { + "data": { + "description": "Array of available model objects. At least one entry is always present.", + "example": [ + { + "capabilities": [ + "image" + ], + "context_window": 200000, + "default": true, + "id": "claude-sonnet-4-6", + "input_media_formats": [ + "string" + ], + "name": "Example Name", + "output_media_formats": [ + "string" + ] + } + ], + "items": { + "description": "An AI model available on the platform. Returned in model-listing responses so clients can populate model pickers and resolve the platform default.", + "example": { + "capabilities": [ + "image" + ], + "context_window": 200000, + "default": true, + "id": "claude-sonnet-4-6", + "input_media_formats": [ + "string" + ], + "name": "Example Name", + "output_media_formats": [ + "string" + ] + }, + "properties": { + "capabilities": { + "description": "Machine-readable model capabilities. `\"image\"` marks image-input chat, `\"search\"` marks built-in web search, and `\"thinking\"` marks models with configurable reasoning. Empty when the catalog entry declares no special capabilities.", + "example": [ + "image" + ], + "items": { + "enum": [ + "image", + "search", + "thinking" + ], + "type": "string" + }, + "type": "array" + }, + "context_window": { + "description": "Maximum context-window size in tokens this model accepts, when the platform publishes it. Use it to size prompt/history against the real window rather than a hardcoded default. `null` for entries whose window the platform does not report (e.g. legacy or mock model listings); clients should apply a conservative fallback in that case.", + "example": 200000, + "nullable": true, + "type": "integer" + }, + "default": { + "description": "`true` for the model the platform selects when an agent has no `default_model` configured, or for the system-wide fallback in image-generation contexts. Exactly one entry in any given model list carries this flag.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Provider-assigned model identifier used when specifying a model on API requests, e.g. `\"claude-sonnet-4-6\"` or `\"gemini-2.5-flash\"`.", + "example": "claude-sonnet-4-6", + "type": "string" + }, + "input_media_formats": { + "description": "MIME types accepted in chat `content_parts` image/file inputs for this model. For image-capable chat models this includes values such as `\"image/png\"`. Empty for text-only models.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "name": { + "description": "Human-readable display label for this model, e.g. `\"Claude Sonnet 4.6\"` or `\"Gemini 3.5 Flash (thinking)\"`. Render this value directly in pickers rather than attempting to parse or transform `id`. Falls back to the `id` string when the catalog entry does not declare an explicit name.", + "example": "Example Name", + "type": "string" + }, + "output_media_formats": { + "description": "MIME types this model can emit as media in chat responses. Empty for text-output models, including image-understanding models that only return text.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "default", + "capabilities", + "input_media_formats", + "output_media_formats" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + } + }, + "summary": "List available AI models", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/ai/embedding/similarity_comparison": { + "post": { + "description": "Embeds both texts in one synchronous request using the platform's default\nembedding model, then returns their cosine similarity. The score uses the\nsame `1 - cosine_distance` convention as context retrieval. A score near\n`1.0` indicates similar vector direction; lower scores indicate less similar\ntext. This endpoint is intended for authenticated users interactively\nexploring how the platform's retrieval similarity behaves.\n", + "operationId": "post_api_v1_ai_embedding_similarity_comparison", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "text_a": "string", + "text_b": "string" + }, + "properties": { + "text_a": { + "description": "First text to embed and compare.", + "example": "string", + "type": "string" + }, + "text_b": { + "description": "Second text to embed and compare.", + "example": "string", + "type": "string" + } + }, + "required": [ + "text_a", + "text_b" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "The default embedding model and cosine similarity score.", + "example": { + "model": "string", + "similarity_score": 1.0 + }, + "properties": { + "model": { + "description": "Configured default embedding model key used for both texts.", + "example": "string", + "type": "string" + }, + "similarity_score": { + "description": "Cosine similarity from `-1.0` to `1.0`, computed as `1 - cosine_distance`.", + "example": 1.0, + "type": "number" + } + }, + "required": [ + "model", + "similarity_score" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "402": { + "description": "Payment required — plan does not allow this feature" + }, + "422": { + "description": "Embedding comparison failed" + } + }, + "summary": "Compare the embedding similarity of two texts", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/ai/image/edits": { + "post": { + "description": "Applies a text-guided edit to one or more source images and returns the\nresulting image. Pass the source images as base64-encoded objects in the\n`images` array alongside a `prompt` describing the desired modification.\n\nThe underlying provider is selected by the `model` parameter. Omit `model`\nto use the platform default. Size, quality, style, and format options are\nforwarded to the provider as-is; unsupported combinations for a given model\nreturn a 422 error with the provider's error message.\n\nThis endpoint requires authentication. The request is billed against the\nworkspace associated with the authenticated user.\n", + "operationId": "post_api_v1_ai_image_edits", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "aspect_ratio": "string", + "background": "string", + "height": 1, + "image_size": "string", + "images": [ + { + "image_data": "string", + "image_type": "image/png" + } + ], + "model": "string", + "output_format": "string", + "prompt": "string", + "quality": "string", + "size": "string", + "style": "string", + "width": 1 + }, + "properties": { + "aspect_ratio": { + "description": "Desired aspect ratio of the output, e.g. `\"1:1\"` or `\"16:9\"`. Not supported by all models; omit to use the model's default.", + "example": "string", + "type": "string" + }, + "background": { + "description": "Background treatment for the output. Accepted values and behavior are model-dependent.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Explicit output height in pixels. Takes precedence over `size` when both are provided. Not supported by all models.", + "example": 1, + "type": "integer" + }, + "image_size": { + "description": "Output resolution tier for Gemini models, e.g. `\"1K\"`, `\"2K\"`, or `\"4K\"`. Ignored by non-Gemini models.", + "example": "string", + "type": "string" + }, + "images": { + "description": "One or more source images to edit. Each image must be supplied as a base64-encoded object.", + "example": [ + { + "image_data": "string", + "image_type": "image/png" + } + ], + "items": { + "description": "An input image supplied to an AI image-editing request. The image must be provided as a base64-encoded string along with its MIME type.", + "example": { + "image_data": "string", + "image_type": "image/png" + }, + "properties": { + "image_data": { + "description": "The raw image content encoded as a base64 string (standard encoding, no line breaks).", + "example": "string", + "type": "string" + }, + "image_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. Must match the actual encoding of `image_data`.", + "example": "image/png", + "type": "string" + } + }, + "required": [ + "image_data", + "image_type" + ], + "type": "object" + }, + "type": "array" + }, + "model": { + "description": "Model identifier to use for editing. Omit to use the platform default image model.", + "example": "string", + "type": "string" + }, + "output_format": { + "description": "Desired MIME type or format for the returned image. Common values: `\"png\"`, `\"jpeg\"`, `\"webp\"`. Defaults to the model's native format.", + "example": "string", + "type": "string" + }, + "prompt": { + "description": "Natural-language description of the edit to apply to the source image(s).", + "example": "string", + "type": "string" + }, + "quality": { + "description": "Quality preset for the output image. Accepted values and behavior are model-dependent.", + "example": "string", + "type": "string" + }, + "size": { + "description": "Output dimensions as a WxH string, e.g. `\"1024x1024\"`. Applies to OpenAI-compatible models. Omit to use the model's default.", + "example": "string", + "type": "string" + }, + "style": { + "description": "Style preset applied to the edit. Accepted values and behavior are model-dependent.", + "example": "string", + "type": "string" + }, + "width": { + "description": "Explicit output width in pixels. Takes precedence over `size` when both are provided. Not supported by all models.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "prompt", + "images" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AIImageResult" + } + } + }, + "description": "The resulting edited image, including base64 data or a URL depending on the model." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "422": { + "description": "Image editing failed" + } + }, + "summary": "Edit an image with a text prompt", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/ai/image/generations": { + "post": { + "description": "Generates one or more images from a natural-language `prompt` using the\nspecified AI image model. The response contains the first generated image;\nuse `n` to request additional images (where supported by the model).\n\nThe underlying provider is selected by the `model` parameter. Omit `model`\nto use the platform default. Size, quality, style, and format options are\nforwarded to the provider as-is; unsupported combinations for a given model\nreturn a 422 error with the provider's error message.\n\nThis endpoint requires authentication. The request is billed against the\nworkspace associated with the authenticated user.\n", + "operationId": "post_api_v1_ai_image_generations", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "aspect_ratio": "string", + "background": "string", + "height": 1, + "image_size": "string", + "model": "string", + "n": 1, + "output_format": "string", + "prompt": "string", + "quality": "string", + "size": "string", + "style": "string", + "width": 1 + }, + "properties": { + "aspect_ratio": { + "description": "Desired aspect ratio of the output, e.g. `\"1:1\"` or `\"16:9\"`. Not supported by all models; omit to use the model's default.", + "example": "string", + "type": "string" + }, + "background": { + "description": "Background treatment for the output. Accepted values and behavior are model-dependent.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Explicit output height in pixels. Takes precedence over `size` when both are provided. Not supported by all models.", + "example": 1, + "type": "integer" + }, + "image_size": { + "description": "Output resolution tier for Gemini models, e.g. `\"1K\"`, `\"2K\"`, or `\"4K\"`. Ignored by non-Gemini models.", + "example": "string", + "type": "string" + }, + "model": { + "description": "Model identifier to use for generation. Omit to use the platform default image model.", + "example": "string", + "type": "string" + }, + "n": { + "description": "Number of images to generate. Defaults to `1`. Values greater than `1` are only supported by models that allow batch generation.", + "example": 1, + "type": "integer" + }, + "output_format": { + "description": "Desired MIME type or format for the returned image. Common values: `\"png\"`, `\"jpeg\"`, `\"webp\"`. Defaults to the model's native format.", + "example": "string", + "type": "string" + }, + "prompt": { + "description": "Natural-language description of the image to generate.", + "example": "string", + "type": "string" + }, + "quality": { + "description": "Quality preset for the output image. Accepted values and behavior are model-dependent.", + "example": "string", + "type": "string" + }, + "size": { + "description": "Output dimensions as a WxH string, e.g. `\"1024x1024\"`. Applies to OpenAI-compatible models. Omit to use the model's default.", + "example": "string", + "type": "string" + }, + "style": { + "description": "Style preset applied to the generated image. Accepted values and behavior are model-dependent.", + "example": "string", + "type": "string" + }, + "width": { + "description": "Explicit output width in pixels. Takes precedence over `size` when both are provided. Not supported by all models.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "prompt" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AIImageResult" + } + } + }, + "description": "The generated image, including base64 data or a URL depending on the model." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "422": { + "description": "Image generation failed" + } + }, + "summary": "Generate an image from a text prompt", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/ai/image/models": { + "get": { + "description": "Returns the list of image generation models available on the platform.\nExactly one entry in the list carries `default: true`, indicating the model\nused when no `model` parameter is supplied to the generation or editing\nendpoints.\n\nThis endpoint requires authentication and reflects the models enabled for\nthe authenticated user's workspace.\n", + "operationId": "get_api_v1_ai_image_models", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Response envelope containing the list of available image models.", + "example": { + "data": [ + { + "capabilities": [ + "image" + ], + "context_window": 200000, + "default": true, + "id": "claude-sonnet-4-6", + "input_media_formats": [ + "string" + ], + "name": "Example Name", + "output_media_formats": [ + "string" + ] + } + ] + }, + "properties": { + "data": { + "description": "Array of available image generation models, including their identifiers, human-readable names, and which one is the platform default.", + "example": [ + { + "capabilities": [ + "image" + ], + "context_window": 200000, + "default": true, + "id": "claude-sonnet-4-6", + "input_media_formats": [ + "string" + ], + "name": "Example Name", + "output_media_formats": [ + "string" + ] + } + ], + "items": { + "description": "An AI model available on the platform. Returned in model-listing responses so clients can populate model pickers and resolve the platform default.", + "example": { + "capabilities": [ + "image" + ], + "context_window": 200000, + "default": true, + "id": "claude-sonnet-4-6", + "input_media_formats": [ + "string" + ], + "name": "Example Name", + "output_media_formats": [ + "string" + ] + }, + "properties": { + "capabilities": { + "description": "Machine-readable model capabilities. `\"image\"` marks image-input chat, `\"search\"` marks built-in web search, and `\"thinking\"` marks models with configurable reasoning. Empty when the catalog entry declares no special capabilities.", + "example": [ + "image" + ], + "items": { + "enum": [ + "image", + "search", + "thinking" + ], + "type": "string" + }, + "type": "array" + }, + "context_window": { + "description": "Maximum context-window size in tokens this model accepts, when the platform publishes it. Use it to size prompt/history against the real window rather than a hardcoded default. `null` for entries whose window the platform does not report (e.g. legacy or mock model listings); clients should apply a conservative fallback in that case.", + "example": 200000, + "nullable": true, + "type": "integer" + }, + "default": { + "description": "`true` for the model the platform selects when an agent has no `default_model` configured, or for the system-wide fallback in image-generation contexts. Exactly one entry in any given model list carries this flag.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Provider-assigned model identifier used when specifying a model on API requests, e.g. `\"claude-sonnet-4-6\"` or `\"gemini-2.5-flash\"`.", + "example": "claude-sonnet-4-6", + "type": "string" + }, + "input_media_formats": { + "description": "MIME types accepted in chat `content_parts` image/file inputs for this model. For image-capable chat models this includes values such as `\"image/png\"`. Empty for text-only models.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "name": { + "description": "Human-readable display label for this model, e.g. `\"Claude Sonnet 4.6\"` or `\"Gemini 3.5 Flash (thinking)\"`. Render this value directly in pickers rather than attempting to parse or transform `id`. Falls back to the `id` string when the catalog entry does not declare an explicit name.", + "example": "Example Name", + "type": "string" + }, + "output_media_formats": { + "description": "MIME types this model can emit as media in chat responses. Empty for text-output models, including image-understanding models that only return text.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "default", + "capabilities", + "input_media_formats", + "output_media_formats" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + } + }, + "summary": "List available image generation models", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/artifacts/{artifact}": { + "delete": { + "description": "Permanently deletes the artifact and all associated file versions. This\noperation is irreversible — deleted artifacts and their file content cannot\nbe recovered.\n\nThe authenticated user must have write access to the artifact's owning team\nor organization. Returns 404 if the artifact does not exist or is not\naccessible to the caller.\n", + "operationId": "delete_api_v1_artifacts__artifact", + "parameters": [ + { + "description": "Artifact ID (`art_...`) of the artifact to delete.", + "example": "string", + "in": "path", + "name": "artifact", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty body. HTTP 204 indicates the artifact and all associated file versions were permanently deleted." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Artifact not found" + } + }, + "summary": "Delete an artifact", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the artifact identified by `artifact`. The response includes metadata\nsuch as name, description, version, and a signed `file_url` for downloading\nthe current file version. Image artifacts also include an `image_source` object\nwith display-ready metadata.\n\nThe authenticated user must have read access to the artifact's owning team or\norganization. Returns 404 if the artifact does not exist or is not accessible\nto the caller.\n", + "operationId": "get_api_v1_artifacts__artifact", + "parameters": [ + { + "description": "Artifact ID (`art_...`) of the artifact to retrieve.", + "example": "string", + "in": "path", + "name": "artifact", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Artifact" + } + } + }, + "description": "The requested artifact, including its current version's file metadata and signed download URL." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Artifact not found" + } + }, + "summary": "Retrieve an artifact", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "put": { + "description": "Updates the metadata and, optionally, the file content of an existing artifact.\nThis endpoint uses optimistic concurrency control: you must supply the artifact's\ncurrent `version` number as `from_version`. If another update has incremented the\nversion since you last fetched the artifact, the request returns 409.\n\nTo replace the artifact's file, include a nested `file` object with Base64\n`data`, `filename`, and `mime_type`. Omitting `file` leaves the existing file\nunchanged. The authenticated user or developer must have write access to the\nartifact's owner.\n", + "operationId": "put_api_v1_artifacts__artifact", + "parameters": [ + { + "description": "Artifact ID (`art_...`) of the artifact to update.", + "example": "string", + "in": "path", + "name": "artifact", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "description": "An example description.", + "file": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "file_content": "string", + "file_content_type": "string", + "file_name": "Example Name", + "from_version": 1, + "name": "Example Name" + }, + "properties": { + "description": { + "description": "New description for the artifact. Omit to leave the existing description unchanged.", + "example": "An example description.", + "type": "string" + }, + "file": { + "description": "Replacement file payload. Omit to leave the current file unchanged.", + "example": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "properties": { + "data": { + "description": "Base64-encoded binary content.", + "example": "string", + "type": "string" + }, + "filename": { + "description": "Original filename for the uploaded file.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the uploaded file.", + "example": "application/json", + "type": "string" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "file_content": { + "description": "Legacy flat Base64 file content. Prefer `file.data`.", + "example": "string", + "type": "string" + }, + "file_content_type": { + "description": "Legacy flat MIME type. Prefer `file.mime_type`.", + "example": "string", + "type": "string" + }, + "file_name": { + "description": "Legacy flat filename. Prefer `file.filename`.", + "example": "Example Name", + "type": "string" + }, + "from_version": { + "description": "The artifact's current version number, used for optimistic concurrency control. Returns 409 if this value does not match the server's current version.", + "example": 1, + "type": "integer" + }, + "name": { + "description": "New display name for the artifact. Omit to leave the existing name unchanged.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "from_version" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Artifact" + } + } + }, + "description": "The artifact after applying the update, reflecting the new version number and any changed metadata or file." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Artifact not found" + }, + "409": { + "description": "Version conflict" + }, + "422": { + "description": "Validation error" + } + }, + "summary": "Update an artifact", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/artifacts/{artifact}/archive": { + "post": { + "description": "Soft-deletes the artifact identified by `artifact`. The artifact record is\nretained in storage but is no longer returned by the list or show endpoints.\n\nThe authenticated user must have write access to the artifact's owning team or\norganization. Attempting to archive an artifact you do not own returns 403.\nAttempting to archive an artifact that does not exist or is already archived\nreturns 404.\n", + "operationId": "post_api_v1_artifacts__artifact_archive", + "parameters": [ + { + "description": "Artifact ID (`art_...`) of the artifact to archive.", + "example": "string", + "in": "path", + "name": "artifact", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Returns 204 No Content on success. The artifact is soft-deleted and no longer accessible through the API." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Artifact not found" + } + }, + "summary": "Archive an artifact", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/artifacts/{artifact}/content": { + "get": { + "description": "Returns the raw binary content of the file stored for the specified artifact.\nThe response `Content-Type` header reflects the artifact file's MIME type, so\nyou can pipe the response body directly to disk or display it in a browser.\n\nBy default the endpoint serves the artifact's current version. Pass the\n`version` parameter to retrieve a specific historical version. The authenticated\nuser must have read access to the artifact's owning team or organization.\n", + "operationId": "get_api_v1_artifacts__artifact_content", + "parameters": [ + { + "description": "Artifact ID (`art_...`) of the artifact whose content to retrieve.", + "example": "string", + "in": "path", + "name": "artifact", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Version number to retrieve. Omit to return the artifact's current version.", + "example": 1, + "in": "query", + "name": "version", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "*/*": { + "schema": { + "format": "binary", + "type": "string" + } + } + }, + "description": "Raw binary content of the artifact file. The `Content-Type` header is set to the artifact's stored MIME type." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Artifact content not found" + }, + "422": { + "description": "Error retrieving content" + } + }, + "summary": "Retrieve raw artifact file content", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/auth/allowed_auth_methods": { + "get": { + "description": "Returns the complete catalogue of authentication methods the platform supports,\nincluding each method's stable slug, user-facing name, and description.\n\nUse this endpoint to render method labels in sign-in UIs or org settings screens\nwithout hardcoding copy or maintaining your own enum list. Results reflect the\nplatform's source-of-truth catalogue and are consistent across all orgs.\n\nThis endpoint requires only a publishable key and is accessible without an active\nuser session, making it suitable for pre-authentication flows such as login page\nrendering or onboarding configuration.\n", + "operationId": "get_api_v1_auth_allowed_auth_methods", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Catalogue of all authentication methods the platform supports.", + "example": { + "data": [ + { + "description": "An example description.", + "name": "Example Name", + "slug": "example-slug" + } + ] + }, + "properties": { + "data": { + "description": "Ordered array of supported auth method objects, each with a stable slug, display name, and description.", + "example": [ + { + "description": "An example description.", + "name": "Example Name", + "slug": "example-slug" + } + ], + "items": { + "description": "A single authentication method supported by the platform, including its stable identifier and user-facing copy.", + "example": { + "description": "An example description.", + "name": "Example Name", + "slug": "example-slug" + }, + "properties": { + "description": { + "description": "One-sentence user-facing explanation of how this auth method works, suitable for display in an auth selection UI.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "Short user-facing label suitable for buttons or list items, e.g. `\"Password\"` or `\"Magic Link\"`.", + "example": "Example Name", + "type": "string" + }, + "slug": { + "description": "Stable machine-readable identifier for this auth method, e.g. `\"password\"` or `\"magic_link\"`. Use this value when enabling or referencing auth methods programmatically.", + "example": "example-slug", + "type": "string" + } + }, + "required": [ + "slug", + "name", + "description" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + } + }, + "summary": "List supported auth methods", + "tags": [ + "auth" + ], + "x-auth": [ + "publishable_key" + ] + } + }, + "/api/v1/auth/login": { + "post": { + "description": "Authenticates a user with an email address and password and returns a short-lived\naccess token, a refresh token, and the authenticated user object. Use the refresh\ntoken with the `/auth/refresh` endpoint to obtain new access tokens without\nre-authenticating.\n\nPassword login must be enabled for the app; apps that have disabled password\nauthentication return HTTP 403. Requests are rate-limited per IP (10 per minute)\nand per email-IP pair (5 per minute) — exceeding either limit returns HTTP 429.\n", + "operationId": "post_api_v1_auth_login", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "email": "user@example.com", + "password": "string" + }, + "properties": { + "email": { + "description": "Email address of the user to authenticate.", + "example": "user@example.com", + "type": "string" + }, + "password": { + "description": "Password for the account associated with the given email.", + "example": "string", + "type": "string" + } + }, + "required": [ + "email", + "password" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokens" + } + } + }, + "description": "Access token, refresh token, and authenticated user object." + }, + "401": { + "description": "Invalid credentials" + }, + "403": { + "description": "Password login is not enabled for this organization" + }, + "429": { + "description": "Rate limited" + } + }, + "summary": "Authenticate with email and password", + "tags": [ + "auth" + ], + "x-auth": [ + "publishable_key" + ] + } + }, + "/api/v1/auth/login/link": { + "post": { + "description": "Sends a magic link to the given email address so an existing user can sign in\nwithout a password. The user clicks the link in their email and is redirected to\n`redirect_uri` with a token; pass that token to `/auth/verify_link` to obtain\nsession tokens.\n\nIf no account exists for the email, the endpoint still returns success to prevent\nemail enumeration — no link is sent in that case. Both `email` and `redirect_uri`\nare required. Requests are rate-limited per IP (10 per minute) and per email-IP pair\n(3 per minute) — exceeding either limit returns HTTP 429. Returns HTTP 204 on success.\n", + "operationId": "post_api_v1_auth_login_link", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "email": "user@example.com", + "redirect_uri": "https://example.com" + }, + "properties": { + "email": { + "description": "Email address of the account to send the magic link to.", + "example": "user@example.com", + "type": "string" + }, + "redirect_uri": { + "description": "URL the user is redirected to after clicking the magic link. The token is appended as a query parameter.", + "example": "https://example.com", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No content" + }, + "400": { + "description": "Missing email or redirect_uri" + }, + "429": { + "description": "Rate limited" + } + }, + "summary": "Request a magic link for login", + "tags": [ + "auth" + ], + "x-auth": [ + "publishable_key" + ], + "x-sdk-name": "request_login_magic_link" + } + }, + "/api/v1/auth/refresh": { + "post": { + "description": "Exchanges a valid refresh token for a new access token and a new refresh token,\nrotating the refresh token on every call. The response also includes the updated\nuser object. Store the new refresh token and discard the old one.\n\nRefresh tokens are single-use — submitting an already-consumed token returns HTTP 401.\nRate limiting is applied per (user, IP) pair when the token can be verified, and\nfalls back to IP-only when it cannot. The limit is 30 exchanges per minute per\nbucket; exceeding it returns HTTP 429.\n", + "operationId": "post_api_v1_auth_refresh", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "refresh_token": "string" + }, + "properties": { + "refresh_token": { + "description": "Refresh token previously issued by a login, registration, or token-refresh response.", + "example": "string", + "type": "string" + } + }, + "required": [ + "refresh_token" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokens" + } + } + }, + "description": "New access token, new refresh token, and the authenticated user object." + }, + "401": { + "description": "Invalid or expired refresh token" + }, + "429": { + "description": "Rate limited" + } + }, + "summary": "Refresh an access token", + "tags": [ + "auth" + ], + "x-auth": [ + "publishable_key" + ] + } + }, + "/api/v1/auth/register": { + "post": { + "description": "Creates a new user account and returns an access token, refresh token, and the new\nuser object. Two registration paths are supported:\n\n- **Team registration**: supply `team_invite` with a valid team invite ID. The new\n user is added to that team immediately upon registration. Returns HTTP 404 if the\n invite is not found.\n- **Standard registration**: supply `password`. An `invite_code` may optionally be\n included for invite-gated apps; an invalid code returns HTTP 404.\n\nExactly one of `team_invite` or `password` must be provided; omitting both returns\nHTTP 400. Password registration must be enabled for the app; disabled apps return\nHTTP 403. The response status is HTTP 201 on success.\n", + "operationId": "post_api_v1_auth_register", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "alias": "string", + "email": "user@example.com", + "full_name": "Example Name", + "invite_code": "string", + "password": "string", + "set_org": true, + "team_invite": "string", + "timezone": "America/New_York" + }, + "properties": { + "alias": { + "description": "Display alias (handle) for the new account.", + "example": "string", + "type": "string" + }, + "email": { + "description": "Email address for the new account.", + "example": "user@example.com", + "type": "string" + }, + "full_name": { + "description": "Full name for the new account.", + "example": "Example Name", + "type": "string" + }, + "invite_code": { + "description": "Invite code for invite-gated registration. Applied only in the standard registration path.", + "example": "string", + "type": "string" + }, + "password": { + "description": "Password for the new account. Required for standard (non-team-invite) registration.", + "example": "string", + "type": "string" + }, + "set_org": { + "description": "Create or reuse an organization from the work-email domain and stamp the new user into it.", + "example": true, + "type": "boolean" + }, + "team_invite": { + "description": "Team invite ID. When provided, the user is added to the team on registration.", + "example": "string", + "type": "string" + }, + "timezone": { + "description": "IANA timezone name for the new account, e.g. `\"America/New_York\"`.", + "example": "America/New_York", + "type": "string" + } + }, + "required": [ + "email" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokens" + } + } + }, + "description": "Access token, refresh token, and the newly created user object." + }, + "400": { + "description": "Missing required parameters" + }, + "403": { + "description": "Password registration is not enabled for this organization" + }, + "404": { + "description": "Team invite not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Register a new user with email and password", + "tags": [ + "auth" + ], + "x-auth": [ + "publishable_key" + ] + } + }, + "/api/v1/auth/register/link": { + "post": { + "description": "Starts a passwordless registration flow by sending a verification link to the given\nemail address. The recipient clicks the link and is redirected to `redirect_uri` with\na token; pass that token to `/auth/verify_link` to complete registration and obtain\nsession tokens.\n\nProfile fields (`full_name`, `alias`, `timezone`) are captured now and applied when\nthe link is verified. Requests are rate-limited per IP (10 per minute) and per\nemail-IP pair (3 per minute) — exceeding either limit returns HTTP 429. Returns\nHTTP 204 on success.\n", + "operationId": "post_api_v1_auth_register_link", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "alias": "string", + "email": "user@example.com", + "full_name": "Example Name", + "redirect_uri": "https://example.com", + "set_org": true, + "timezone": "America/New_York" + }, + "properties": { + "alias": { + "description": "Display alias (handle) for the new account.", + "example": "string", + "type": "string" + }, + "email": { + "description": "Email address to send the registration magic link to.", + "example": "user@example.com", + "type": "string" + }, + "full_name": { + "description": "Full name for the new account.", + "example": "Example Name", + "type": "string" + }, + "redirect_uri": { + "description": "URL the user is redirected to after clicking the registration link. The token is appended as a query parameter.", + "example": "https://example.com", + "type": "string" + }, + "set_org": { + "description": "Create or reuse an organization from the work-email domain during confirmation.", + "example": true, + "type": "boolean" + }, + "timezone": { + "description": "IANA timezone name for the new account, e.g. `\"America/New_York\"`.", + "example": "America/New_York", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No content" + }, + "400": { + "description": "Missing email" + }, + "422": { + "description": "Validation failed" + }, + "429": { + "description": "Rate limited" + } + }, + "summary": "Request a magic link for registration", + "tags": [ + "auth" + ], + "x-auth": [ + "publishable_key" + ], + "x-sdk-name": "request_register_magic_link" + } + }, + "/api/v1/auth/request/link": { + "post": { + "description": "Sends a passwordless magic link to the given email address. If an account with that\nemail already exists, a login link is sent. If no account exists, a registration link\nis sent and the recipient completes sign-up by clicking through. This unified endpoint\nlets you implement a single email-entry UI that handles both cases transparently.\n\nThe `redirect_uri` is validated against the app's registered hosts; an unregistered\nURI returns HTTP 400. Both `email` and `redirect_uri` are required. Requests are\nrate-limited per IP (10 per minute) and per email-IP pair (3 per minute). Returns\nHTTP 204 on success — no body.\n", + "operationId": "post_api_v1_auth_request_link", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "email": "user@example.com", + "redirect_uri": "https://example.com", + "set_org": true + }, + "properties": { + "email": { + "description": "Email address to send the magic link to.", + "example": "user@example.com", + "type": "string" + }, + "redirect_uri": { + "description": "URL the user is redirected to after clicking the magic link. Must be registered with the app.", + "example": "https://example.com", + "type": "string" + }, + "set_org": { + "description": "For a new user, create or reuse an organization from the work-email domain during confirmation.", + "example": true, + "type": "boolean" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No content" + }, + "400": { + "description": "Missing email or redirect_uri" + }, + "422": { + "description": "Validation failed" + }, + "429": { + "description": "Rate limited" + } + }, + "summary": "Request a magic link for login or registration", + "tags": [ + "auth" + ], + "x-auth": [ + "publishable_key" + ], + "x-sdk-name": "request_magic_link" + } + }, + "/api/v1/auth/token": { + "post": { + "description": "Consumes a single-use login token delivered via email and returns an access token,\nrefresh token, and the authenticated user object. One-time tokens are issued by the\npasswordless login flow and expire after a short window; submitting an expired or\nalready-used token returns HTTP 401.\n\nIf `timezone` is provided and the user's current timezone is still the default\n(`\"America/Los_Angeles\"`), the account timezone is updated in the same request.\nRequests are rate-limited to 10 per IP per minute; exceeding this returns HTTP 429.\n", + "operationId": "post_api_v1_auth_token", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "timezone": "America/New_York", + "token": "string" + }, + "properties": { + "timezone": { + "description": "IANA timezone name to apply to the account if the account timezone is still the default, e.g. `\"Europe/London\"`. Omit to leave the timezone unchanged.", + "example": "America/New_York", + "type": "string" + }, + "token": { + "description": "Single-use login token extracted from the magic link or email code flow.", + "example": "string", + "type": "string" + } + }, + "required": [ + "token" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokens" + } + } + }, + "description": "Access token, refresh token, and the authenticated user object." + }, + "400": { + "description": "Missing token" + }, + "401": { + "description": "Invalid or expired token" + }, + "429": { + "description": "Rate limited" + }, + "500": { + "description": "Token exchange failed" + } + }, + "summary": "Exchange a one-time login token for session tokens", + "tags": [ + "auth" + ], + "x-auth": [ + "publishable_key" + ], + "x-sdk-name": "exchange_login_token" + } + }, + "/api/v1/auth/verify/link": { + "post": { + "description": "Consumes a single-use token from a magic link URL and returns an access token,\nrefresh token, and the authenticated user object. This endpoint completes both the\nlogin flow (initiated by `/auth/request_login_link`) and the registration flow\n(initiated by `/auth/request_register_link` or `/auth/request_link`).\n\nExtract the token from the `token` query parameter of the magic link redirect URI\nand POST it here. Expired or already-used tokens return HTTP 401 — expired links\ncarry the error code `expired_token`, unknown or already-used tokens carry\n`invalid_or_expired_token`. If the app has disabled passwordless authentication\nthe request returns HTTP 403. Rate-limited to 10 requests per IP per minute —\nexceeding this returns HTTP 429.\n", + "operationId": "post_api_v1_auth_verify_link", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "token": "string" + }, + "properties": { + "token": { + "description": "Single-use magic link token extracted from the redirect URI query parameter.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokens" + } + } + }, + "description": "Access token, refresh token, and the authenticated user object." + }, + "400": { + "description": "Missing token" + }, + "401": { + "description": "Invalid or expired token" + }, + "403": { + "description": "Passwordless login is not enabled for this organization" + }, + "429": { + "description": "Rate limited" + } + }, + "summary": "Verify a magic link token", + "tags": [ + "auth" + ], + "x-auth": [ + "publishable_key" + ], + "x-sdk-name": "verify_magic_link" + } + }, + "/api/v1/automation_runs/{automation_run}": { + "get": { + "description": "Returns a single automation run by ID.\n\nPublic v1 path: `GET /api/v1/automation_runs/:automation_run`.\nDeveloper app-scoped path (legacy shape, same module):\n`GET /protected/api/v1/developer/apps/:app/automations/runs/:automation_run`.\n\nAny automation type is accepted (`trigger`, `scheduled`, or `invoked`).\nResolution is viewer-scoped (AppScope + OrgScope): a run the caller cannot\nsee returns 404.\n", + "operationId": "get_api_v1_automation_runs__automation_run", + "parameters": [ + { + "description": "Automation run ID (`arun_...`).", + "example": "string", + "in": "path", + "name": "automation_run", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AutomationRun" + } + } + }, + "description": "The requested automation run." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Automation run not found" + } + }, + "summary": "Retrieve an automation run", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/automation_runs/{automation_run}/journal": { + "get": { + "description": "Returns durable workflow journal entries for an automation run.\n\nPublic v1 path: `GET /api/v1/automation_runs/:automation_run/journal`.\nDeveloper app-scoped path (legacy shape, same module):\n`GET /protected/api/v1/developer/apps/:app/automations/runs/:automation_run/journal`.\n\nAny automation type is accepted. Resolution is viewer-scoped\n(AppScope + OrgScope). An authorized run without a journal returns\n`journal: null` and an empty `data` array with HTTP 200.\n", + "operationId": "get_api_v1_automation_runs__automation_run_journal", + "parameters": [ + { + "description": "Automation run ID (`atr_...`) whose journal to retrieve.", + "example": "string", + "in": "path", + "name": "automation_run", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of entries to return. Defaults to 50; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor from the previous response's `after_cursor` field.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunJournalPage" + } + } + }, + "description": "Forward-paginated automation run journal entries." + }, + "400": { + "description": "Invalid cursor" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Automation run not found" + } + }, + "summary": "List an automation run journal", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/automation_runs/{automation_run}/stream": { + "get": { + "description": "Opens a Server-Sent Events connection that emits a `run_update` event whenever\nthe invoked automation run's status changes, replaying the current status on\nconnect and closing on a terminal status (`completed`, `failed`, `cancelled`)\nor after the max stream duration.\n", + "operationId": "get_api_v1_automation_runs__automation_run_stream", + "parameters": [ + { + "description": "ID of the invoked automation run.", + "example": "string", + "in": "path", + "name": "automation_run", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "text/event-stream": { + "schema": { + "$ref": "#/components/schemas/AutomationRun" + } + } + }, + "description": "Server-Sent Events stream" + }, + "404": { + "description": "Automation run not found" + } + }, + "summary": "Stream automation run status", + "x-auth": [ + "publishable_key", + "bearer" + ], + "x-sdk-streaming": { + "events": { + "run_update": { + "$ref": "#/components/schemas/AutomationRun" + } + }, + "type": "sse" + } + } + }, + "/api/v1/automations/{automation}/invoke": { + "post": { + "description": "Triggers a single run of an automation that has `type: \"invoked\"`. Returns\nthe resulting automation run object, which you can use to poll or display\nrun status.\n\nBoth server-to-server (secret key) and user (publishable key + JWT) auth\nare supported. The automation's `invoke_auth` setting controls which auth\nmodes are accepted; requests using an unsupported mode are rejected with\n403. For server-to-server callers the run executes under the identity\nconfigured in the automation's `run_as_user` or `run_as_agent` fields. For\nauthenticated user callers the invoking user's identity is used\nautomatically.\n\nIf you supply an `idempotency_key`, a second request with the same key\nreturns the existing run rather than creating a new one.\n\n## Body fields\n\n* `payload` — free-form invoke input. **This is the workflow parameters**:\n validated against `input_schema` when configured, stored as\n `event_payload`, and becomes the workflow `$` after trigger unwrap\n (e.g. `{{$.bug}}` for `{\"bug\":\"upload fails\"}`).\n* `participants` — optional map of symbolic participant refs to agent ids\n for distributed `embed_agent` nodes, e.g.\n `{\"investigator\":\"agi_...\",\"evaluator\":\"agi_...\"}`. Stored in the\n run's top-level `participants` field (not inside free-form payload) and\n exposed to workflows through their system context.\n\nSame top-level `payload` + `participants` shape as routine invoke.\n", + "operationId": "post_api_v1_automations__automation_invoke", + "parameters": [ + { + "description": "Automation ID (`auto_...`) or `lookup_key` of the automation to invoke.", + "example": "string", + "in": "path", + "name": "automation", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "idempotency_key": "string", + "participants": {}, + "payload": {} + }, + "properties": { + "idempotency_key": { + "description": "Unique key to deduplicate concurrent or retried invocations. A second request with the same key returns the existing run instead of creating a new one.", + "example": "string", + "type": "string" + }, + "participants": { + "description": "Map of symbolic participant refs to agent ids (`agi_...` or UUID) for distributed embed_agent handoffs. Stored in the run's top-level `participants` field.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Free-form invoke input — the workflow parameters. Validated against the automation's `input_schema` when configured. Stored as `event_payload` and becomes the workflow `$` after trigger unwrap (e.g. `{{$.bug}}`).", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AutomationRun" + } + } + }, + "description": "The automation run created by this invocation." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Automation not found" + }, + "409": { + "description": "Idempotency conflict" + }, + "422": { + "description": "Unprocessable entity" + } + }, + "summary": "Invoke an automation", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/bug_reports": { + "post": { + "description": "Creates a bug report or freeform feedback entry on behalf of the authenticated user.\nThe `description` is stored in full; the `context` blob is stored verbatim and surfaced\nduring triage. Callers should include relevant session identifiers (URL, thread ID, etc.)\nin `context` to speed up reproduction.\n\nThis endpoint requires authentication. Submissions are rate-limited to 10 reports per\nuser per hour; exceeding that limit returns 429. The `client` value must be one of the\nrecognised string identifiers listed below — an unrecognised value returns 400.\n", + "operationId": "post_api_v1_bug_reports", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "client": "string", + "client_version": "string", + "context": {}, + "description": "An example description." + }, + "properties": { + "client": { + "description": "Identifier of the submitting client. One of `\"agent_network_web\"`, `\"cli\"`, or `\"developer_portal\"`.", + "example": "string", + "type": "string" + }, + "client_version": { + "description": "Build SHA or package version of the client.", + "example": "string", + "type": "string" + }, + "context": { + "description": "Optional client-shaped context blob; ≤5 KB serialized. Stored verbatim and surfaced for triage — clients commonly include url, user_agent, thread_id, message_id, etc.", + "example": {}, + "type": "object" + }, + "description": { + "description": "Freeform report text. 1–10,000 chars after trim.", + "example": "An example description.", + "type": "string" + } + }, + "required": [ + "description", + "client", + "client_version" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BugReport" + } + } + }, + "description": "The created bug report record." + }, + "400": { + "description": "Bad request — invalid client value" + }, + "401": { + "description": "Unauthorized" + }, + "422": { + "description": "Validation failed — empty description, oversized payload, or other changeset error" + }, + "429": { + "description": "Rate limit exceeded — 10 reports per user per hour" + } + }, + "summary": "Submit a bug report", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config": { + "get": { + "description": "Returns all configs owned by the specified owner. Exactly one owner selector\n(`team`, `user`, or `agent`) must be provided. Passing an unknown or\ninaccessible owner returns an empty `data` array rather than an error, to\navoid leaking information about which teams, users, or agents exist.\n\nUse the `kind`, `lookup_key`, `path_prefix`, `parents`, and\n`parent_solutions` params to narrow results. Private config kinds are always\nexcluded from the response regardless of the viewer's permissions.\n\nResults are not paginated; all matching configs are returned in a single\nresponse.\n", + "operationId": "get_api_v1_config", + "parameters": [ + { + "description": "Team ID (`team_...`) whose configs to list. Mutually exclusive with `user` and `agent`.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) whose configs to list. Defaults to the current user when the viewer is a user and no owner selector is provided. Mutually exclusive with `team` and `agent`.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Agent ID (`agt_...`) whose configs to list. Mutually exclusive with `team` and `user`.", + "example": "string", + "in": "query", + "name": "agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter results to configs of this kind, e.g. `\"Agent\"` or `\"APITool\"`. Omit to return configs of all non-private kinds.", + "example": "string", + "in": "query", + "name": "kind", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to the config with exactly this `lookup_key`. Returns at most one result.", + "example": "string", + "in": "query", + "name": "lookup_key", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to configs whose `virtual_path` starts with this prefix, e.g. `\"my-agent/\"`. Useful for listing files within a folder.", + "example": "string", + "in": "query", + "name": "path_prefix", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to configs that are children of any of the listed parent config IDs (`cfg_...`). Pass a single ID to retrieve all children of one bundle.", + "example": [ + "string" + ], + "in": "query", + "name": "parents", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Filter to configs that were imported as part of any of the listed solution config IDs (`cfg_...`). Useful for identifying all files that arrived with a given solution.", + "example": [ + "string" + ], + "in": "query", + "name": "parent_solutions", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "The list of configs matching the requested owner and filters.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "current_version": { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + }, + "id": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "is_archived": true, + "kind": "Agent", + "lookup_key": "string", + "mime_type": "application/json", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "parent_solution": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "raw_content": "string", + "relative_path": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "virtual_path": "agents/my-agent.yaml" + } + ] + }, + "properties": { + "data": { + "description": "Array of config objects matching the query.", + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "current_version": { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + }, + "id": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "is_archived": true, + "kind": "Agent", + "lookup_key": "string", + "mime_type": "application/json", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "parent_solution": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "raw_content": "string", + "relative_path": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "virtual_path": "agents/my-agent.yaml" + } + ], + "items": { + "description": "A versioned config file owned by a team or user, representing a typed artifact such as an agent definition or API tool specification.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "current_version": { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + }, + "id": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "is_archived": true, + "kind": "Agent", + "lookup_key": "string", + "mime_type": "application/json", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "parent_solution": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "raw_content": "string", + "relative_path": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "virtual_path": "agents/my-agent.yaml" + }, + "properties": { + "agent": { + "description": "Agent ID (`agt_...`) associated with this config. `null` if not linked to an agent.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When this config was first created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "current_version": { + "description": "The most recently saved version of this config. `null` if the config has never been saved with content.", + "example": { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + }, + "properties": { + "change_description": { + "description": "Human-readable summary of what changed in this version, as provided by the author. `null` if no description was supplied.", + "example": "An example description.", + "type": "string" + }, + "content_hash": { + "description": "SHA-256 digest of the raw config content encoded as `sha256:`. Uses the same algorithm as the CLI `computeContentHash` helper. `null` for versions created before this field was introduced.", + "example": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "type": "string" + }, + "created_at": { + "description": "When this config version was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "data": { + "description": "Arbitrary structured metadata stored alongside this version. `null` when no extra data was provided.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Config version ID (`cfv_...`).", + "example": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this config version. `null` for personal configs.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Sandbox ID (`sbx_...`) this version was saved under. `null` for production configs.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution_config_version": { + "description": "Config version ID (`cfv_...`) for the Solution version this config version was installed from. `null` for standalone configs and legacy rows.", + "example": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "version_number": { + "description": "Monotonically increasing integer identifying this version within the config. Starts at 1.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "version_number" + ], + "type": "object" + }, + "id": { + "description": "Config ID (`cfg_...`).", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_archived": { + "description": "Whether this config has been archived. Archived configs are hidden from default listings but remain accessible by ID.", + "example": true, + "type": "boolean" + }, + "kind": { + "description": "Type of config, e.g. `\"Agent\"` or `\"APITool\"`. Determines which fields and validation rules apply.", + "example": "Agent", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined key used to look up this config without knowing its ID. `null` if not set.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the config's content, e.g. `\"text/yaml\"`. `null` if not determined.", + "example": "application/json", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) this config belongs to. `null` for configs not scoped to an org.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "Parent bundle config ID (`cfg_...`). Present only for configs that are children of a bundle; `null` otherwise.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent_solution": { + "description": "ID (`cfg_...`) of the solution config this config was imported with. `null` if the config was not imported via a solution.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "raw_content": { + "description": "Raw file content as a string. Populated only for system configs; `null` for user-owned configs.", + "example": "string", + "type": "string" + }, + "relative_path": { + "description": "Path of this config relative to its parent bundle root. Present only for bundle children; `null` otherwise.", + "example": "string", + "type": "string" + }, + "sandbox": { + "description": "Sandbox identifier this config belongs to. `null` for production configs.", + "example": "string", + "type": "string" + }, + "team": { + "description": "Team ID (`tea_...`) that owns this config. `null` for personal (user-scoped) configs.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When this config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) who owns this config. `null` for team-scoped configs.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "virtual_path": { + "description": "Logical path uniquely identifying this config within its team, e.g. `\"agents/my-agent.yaml\"`. `null` for configs without an explicit path.", + "example": "agents/my-agent.yaml", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Bad request - owner required" + }, + "401": { + "description": "Unauthorized" + } + }, + "summary": "List configs", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new config and its first version. Returns 201 on success.\n\nA config is uniquely identified within an app + org scope by its\n`virtual_path` or `lookup_key`. Creating a config at a path that already\nexists (including archived configs) returns 409. To adopt an existing config\nat that path and re-own it instead, pass `take_ownership: true` — this\nrequires modify rights on the existing row (developer or all-powerful viewer).\n\nThe owner is resolved from the explicit selector params (`team`, `user`,\n`agent`, or `system`). Developer and all-powerful viewers default to system\nownership when no explicit selector is provided. Exactly one owner selector\nmay be set; conflicting selectors return 422.\n\nRequires app scope.\n", + "operationId": "post_api_v1_config", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "change_description": "An example description.", + "data": {}, + "data_encoding": "string", + "kind": "string", + "lookup_key": "string", + "mime_type": "application/json", + "org": "string", + "parent": "string", + "parent_solution": "string", + "raw_content": "string", + "relative_path": "string", + "system": true, + "take_ownership": true, + "team": "string", + "user": "string", + "virtual_path": "string" + }, + "properties": { + "agent": { + "description": "Agent ID (`agt_...`) to assign as the config owner. Mutually exclusive with `team`, `user`, and `system`.", + "example": "string", + "type": "string" + }, + "change_description": { + "description": "Human-readable description of this initial version, stored on the version record.", + "example": "An example description.", + "type": "string" + }, + "data": { + "description": "Arbitrary key-value metadata stored on the version alongside the content.", + "example": {}, + "type": "object" + }, + "data_encoding": { + "description": "Encoding of `raw_content`. Omit or set `\"raw\"` for literal content; set `\"base64\"` when sending binary content such as images or PDFs in JSON.", + "example": "string", + "type": "string" + }, + "kind": { + "description": "Config kind that determines the schema and behavior of the config, e.g. `\"Agent\"` or `\"APITool\"`.", + "example": "string", + "type": "string" + }, + "lookup_key": { + "description": "Optional stable key for looking up this config independent of its `virtual_path`. Must be unique within the app + org scope across all owners.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of `raw_content`, e.g. `\"application/x-yaml\"` or `\"application/json\"`.", + "example": "application/json", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) to scope the config to a specific org.", + "example": "string", + "type": "string" + }, + "parent": { + "description": "Parent config ID (`cfg_...`) for bundle children, e.g. files belonging to a Skill. Required together with `relative_path` when creating a child config.", + "example": "string", + "type": "string" + }, + "parent_solution": { + "description": "Solution config ID (`cfg_...`) that this config was imported with. Records provenance for configs that arrive as part of a solution bundle.", + "example": "string", + "type": "string" + }, + "raw_content": { + "description": "Raw content bytes for the first version. Accepted formats depend on `mime_type`; typical values are YAML or JSON text.", + "example": "string", + "type": "string" + }, + "relative_path": { + "description": "Path of this config within its parent bundle, e.g. `\"prompts/system.md\"`. Required when `parent` is set.", + "example": "string", + "type": "string" + }, + "system": { + "description": "Set `true` to create a system-owned config (no team, user, or agent owner). Requires a developer, all-powerful, or app system-user viewer, or an org admin creating an org-scoped system config. Mutually exclusive with `team`, `user`, and `agent`.", + "example": true, + "type": "boolean" + }, + "take_ownership": { + "description": "When `true` and a config already exists at the specified `virtual_path` or `lookup_key` under a different owner, adopt that config rather than returning 409: the existing row is re-owned to the requested owner, unarchived if necessary, and this content is saved as its next version. Requires modify rights on the existing row (developer or all-powerful viewer).", + "example": true, + "type": "boolean" + }, + "team": { + "description": "Team ID (`team_...`) to assign as the config owner. Mutually exclusive with `user`, `agent`, and `system`.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) to assign as the config owner. Mutually exclusive with `team`, `agent`, and `system`.", + "example": "string", + "type": "string" + }, + "virtual_path": { + "description": "Human-readable path that uniquely identifies the config within its owner scope, e.g. `\"my-agent/v1\"`. Must be unique within the app + org + owner combination.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind", + "raw_content", + "mime_type" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Config" + } + } + }, + "description": "The newly created config, including its first version." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "409": { + "description": "Conflict - a config with this path/lookup_key already exists" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create a config", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/encrypt_secret": { + "post": { + "description": "Encrypts a plaintext secret and returns a ciphertext string safe for\nembedding directly in config content using the `secret_value!` interpolation\nsyntax. The ciphertext is bound to the app's (or org's) key-encryption key\n(KEK) so it can only be decrypted at runtime within the same scope.\n\nWhen `org` is provided, the KEK for that org is used; otherwise the\nviewer's own org KEK is used, falling back to the app-level KEK for viewers\nwith no org context.\n\nThe plaintext is never stored. Requires app scope.\n", + "operationId": "post_api_v1_config_encrypt_secret", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "org": "string", + "plaintext": "string" + }, + "properties": { + "org": { + "description": "Organization ID (`org_...`) whose KEK to use for encryption. Overrides the viewer's own org. Omit to use the viewer's org KEK, or the app-level KEK when the viewer has no org context.", + "example": "string", + "type": "string" + }, + "plaintext": { + "description": "The secret value to encrypt. Never stored; only the resulting ciphertext is returned.", + "example": "string", + "type": "string" + } + }, + "required": [ + "plaintext" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "The encrypted ciphertext ready for embedding in a config.", + "example": { + "encrypted_value": "string" + }, + "properties": { + "encrypted_value": { + "description": "Encrypted ciphertext string. Embed this in config content using the `secret_value!` interpolation syntax to have it decrypted at runtime.", + "example": "string", + "type": "string" + } + }, + "required": [ + "encrypted_value" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "422": { + "description": "Encryption failed" + } + }, + "summary": "Encrypt a secret for use in a config", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/facets": { + "get": { + "description": "Returns the distinct config kinds and leading `virtual_path` prefixes\navailable to the viewer, each with a count of matching configs. Use this\nto populate filter UI dropdowns without making a full list request.\n\nThe counts reflect every config the viewer can see in the requested scope,\nindependent of any kind, path-prefix, or lookup-key filters that might be\napplied on a concurrent list request. This means the UI always shows every\noption the viewer could pick, not just the values on the current filtered page.\n\nScoping follows the same rules as the list endpoint: developer and\nall-powerful viewers see facets across all owners in the app; org-scoped\nviewers receive their own configs' facets merged with system-owned facets;\nall other viewers see only their resolved owner's configs.\n", + "operationId": "get_api_v1_config_facets", + "parameters": [ + { + "description": "App ID (`app_...`). Present when mounted under the developer scope; injected automatically.", + "example": "string", + "in": "query", + "name": "app", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Team ID (`team_...`) to scope facets to that team's configs. Mutually exclusive with `user`.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) to scope facets to that user's configs. Defaults to the current user when the viewer is a user and no selector is provided. Mutually exclusive with `team`.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Organization ID (`org_...`) to narrow facets to configs belonging to that org.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfigFacets" + } + } + }, + "description": "Distinct config kinds and `virtual_path` prefixes with per-value counts." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + } + }, + "summary": "List config facets", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/kinds": { + "get": { + "description": "Returns all config kinds registered in the platform, sorted alphabetically by name.\nEach entry describes a type of configuration object (e.g., `\"Agent\"`, `\"APITool\"`) and\nindicates whether a JSON schema and a YAML sample are available for it.\n\nAny authenticated user may call this endpoint; no ownership scope is required.\nPass one or more `kind` values to restrict the response to those specific kinds.\nOmit the parameter to receive the full list of non-private kinds.\n", + "operationId": "get_api_v1_config_kinds", + "parameters": [ + { + "description": "One or more config kind names to include in the response (e.g., `\"Agent\"`, `\"APITool\"`). Omit to return all non-private kinds.", + "example": [ + "string" + ], + "in": "query", + "name": "kind", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Object containing the array of matching config kinds.", + "example": { + "data": [ + { + "classification": "root", + "description": "An example description.", + "kind": "Agent", + "sample_available": true, + "schema_available": true + } + ] + }, + "properties": { + "data": { + "description": "Array of config kind objects, sorted alphabetically by `kind` name.", + "example": [ + { + "classification": "root", + "description": "An example description.", + "kind": "Agent", + "sample_available": true, + "schema_available": true + } + ], + "items": { + "description": "A config kind entry describing a supported config type, including its classification, schema availability, and human-readable documentation.", + "example": { + "classification": "root", + "description": "An example description.", + "kind": "Agent", + "sample_available": true, + "schema_available": true + }, + "properties": { + "classification": { + "description": "Structural role of this kind. `\"root\"` kinds are standalone configs; `\"supplemental\"` kinds extend or augment a root config.", + "example": "root", + "type": "string" + }, + "description": { + "description": "Markdown prose describing what this config kind represents and how to use it. `null` when no description has been registered for this kind.", + "example": "An example description.", + "type": "string" + }, + "kind": { + "description": "The config kind identifier (e.g., `\"Agent\"`, `\"APITool\"`). Used as the `kind` value when creating or filtering configs.", + "example": "Agent", + "type": "string" + }, + "sample_available": { + "description": "`true` when a sample YAML document is available for this kind via the schema endpoint.", + "example": true, + "type": "boolean" + }, + "schema_available": { + "description": "`true` when a JSON Schema definition is available for this kind via the schema endpoint.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "kind", + "sample_available", + "schema_available", + "classification" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + } + }, + "summary": "List config kinds", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/kinds/{kind}/schema": { + "get": { + "description": "Returns the JSON schema and a YAML sample for a single config kind. Use this to\nunderstand the structure a config object of that kind must follow before creating\nor validating one.\n\nThe `json_schema` field is `null` when the kind has no machine-readable schema\ndefined. The `sample_yaml` field is `null` when no sample is available. Any\nauthenticated user may call this endpoint; no ownership scope is required.\n\nReturns 404 if the kind name does not match a registered, non-private config kind.\n", + "operationId": "get_api_v1_config_kinds__kind_schema", + "parameters": [ + { + "description": "Name of the config kind to retrieve (e.g., `\"Agent\"`, `\"APITool\"`). Must match a registered, non-private kind exactly.", + "example": "string", + "in": "path", + "name": "kind", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfigKindSchema" + } + } + }, + "description": "The JSON schema and YAML sample for the requested config kind." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Kind not found" + } + }, + "summary": "Retrieve a config kind schema", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/system": { + "get": { + "description": "Returns a paginated list of system (template) configs from the filesystem-backed\nmanifest. Results are always ordered by `virtual_path` ascending.\n\nFilter by one or more config kinds using `kind` (single value) or `kinds` (array).\nBoth filters may be supplied together for backward compatibility; `kinds` takes\nprecedence when both are present. Exclude specific path namespaces with\n`excluded_path_prefixes`.\n\nUse `page` and `page_size` to paginate. Page size is clamped to a maximum of 200;\nrequests exceeding this limit are silently clamped rather than rejected.\n", + "operationId": "get_api_v1_config_system", + "parameters": [ + { + "description": "Filter results to a single config kind, e.g. `\"Agent\"` or `\"APITool\"`. Use `kinds` to filter by multiple kinds at once.", + "example": "string", + "in": "query", + "name": "kind", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter results to configs whose `kind` is in this list. When both `kind` and `kinds` are provided, `kinds` takes precedence.", + "example": [ + "string" + ], + "in": "query", + "name": "kinds", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Exclude configs whose `virtual_path` starts with any of the listed string prefixes.", + "example": [ + "string" + ], + "in": "query", + "name": "excluded_path_prefixes", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Page number to retrieve, 1-indexed. Defaults to `1`.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of results per page. Defaults to `50`; maximum is `200`. Values above the maximum are clamped to `200`.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Paginated list of system configs, ordered by `virtual_path` ascending.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "current_version": { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + }, + "id": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "is_archived": true, + "kind": "Agent", + "lookup_key": "string", + "mime_type": "application/json", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "parent_solution": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "raw_content": "string", + "relative_path": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "virtual_path": "agents/my-agent.yaml" + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 1, + "total_entries": 1, + "total_pages": 1 + }, + "properties": { + "data": { + "description": "Array of system config objects for the current page.", + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "current_version": { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + }, + "id": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "is_archived": true, + "kind": "Agent", + "lookup_key": "string", + "mime_type": "application/json", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "parent_solution": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "raw_content": "string", + "relative_path": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "virtual_path": "agents/my-agent.yaml" + } + ], + "items": { + "description": "A versioned config file owned by a team or user, representing a typed artifact such as an agent definition or API tool specification.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "current_version": { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + }, + "id": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "is_archived": true, + "kind": "Agent", + "lookup_key": "string", + "mime_type": "application/json", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "parent_solution": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "raw_content": "string", + "relative_path": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "virtual_path": "agents/my-agent.yaml" + }, + "properties": { + "agent": { + "description": "Agent ID (`agt_...`) associated with this config. `null` if not linked to an agent.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When this config was first created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "current_version": { + "description": "The most recently saved version of this config. `null` if the config has never been saved with content.", + "example": { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + }, + "properties": { + "change_description": { + "description": "Human-readable summary of what changed in this version, as provided by the author. `null` if no description was supplied.", + "example": "An example description.", + "type": "string" + }, + "content_hash": { + "description": "SHA-256 digest of the raw config content encoded as `sha256:`. Uses the same algorithm as the CLI `computeContentHash` helper. `null` for versions created before this field was introduced.", + "example": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "type": "string" + }, + "created_at": { + "description": "When this config version was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "data": { + "description": "Arbitrary structured metadata stored alongside this version. `null` when no extra data was provided.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Config version ID (`cfv_...`).", + "example": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this config version. `null` for personal configs.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Sandbox ID (`sbx_...`) this version was saved under. `null` for production configs.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution_config_version": { + "description": "Config version ID (`cfv_...`) for the Solution version this config version was installed from. `null` for standalone configs and legacy rows.", + "example": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "version_number": { + "description": "Monotonically increasing integer identifying this version within the config. Starts at 1.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "version_number" + ], + "type": "object" + }, + "id": { + "description": "Config ID (`cfg_...`).", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_archived": { + "description": "Whether this config has been archived. Archived configs are hidden from default listings but remain accessible by ID.", + "example": true, + "type": "boolean" + }, + "kind": { + "description": "Type of config, e.g. `\"Agent\"` or `\"APITool\"`. Determines which fields and validation rules apply.", + "example": "Agent", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined key used to look up this config without knowing its ID. `null` if not set.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the config's content, e.g. `\"text/yaml\"`. `null` if not determined.", + "example": "application/json", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) this config belongs to. `null` for configs not scoped to an org.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "Parent bundle config ID (`cfg_...`). Present only for configs that are children of a bundle; `null` otherwise.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent_solution": { + "description": "ID (`cfg_...`) of the solution config this config was imported with. `null` if the config was not imported via a solution.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "raw_content": { + "description": "Raw file content as a string. Populated only for system configs; `null` for user-owned configs.", + "example": "string", + "type": "string" + }, + "relative_path": { + "description": "Path of this config relative to its parent bundle root. Present only for bundle children; `null` otherwise.", + "example": "string", + "type": "string" + }, + "sandbox": { + "description": "Sandbox identifier this config belongs to. `null` for production configs.", + "example": "string", + "type": "string" + }, + "team": { + "description": "Team ID (`tea_...`) that owns this config. `null` for personal (user-scoped) configs.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When this config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) who owns this config. `null` for team-scoped configs.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "virtual_path": { + "description": "Logical path uniquely identifying this config within its team, e.g. `\"agents/my-agent.yaml\"`. `null` for configs without an explicit path.", + "example": "agents/my-agent.yaml", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "has_next": { + "description": "`true` when a subsequent page of results exists.", + "example": true, + "type": "boolean" + }, + "has_prev": { + "description": "`true` when a previous page of results exists.", + "example": true, + "type": "boolean" + }, + "page": { + "description": "The current page number (1-indexed).", + "example": 1, + "type": "integer" + }, + "page_size": { + "description": "Number of results returned per page.", + "example": 1, + "type": "integer" + }, + "total_entries": { + "description": "Total number of system configs matching the applied filters across all pages.", + "example": 1, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages given the current `page_size`.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "data", + "page", + "page_size", + "total_entries", + "total_pages", + "has_next", + "has_prev" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + } + }, + "summary": "List system configs", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/system/facets": { + "get": { + "description": "Returns the distinct `kind` values and leading `virtual_path` prefixes present\nin the system (template) config manifest, each accompanied by a count of matching\nconfigs. Use this data to populate filter UIs or to determine which config kinds\nare available before listing or cloning.\n\nThe response reflects the filesystem-backed template manifest and does not include\nuser- or team-owned configs.\n", + "operationId": "get_api_v1_config_system_facets", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfigFacets" + } + } + }, + "description": "Aggregated facet data containing distinct config kinds and path prefixes, each with a count of matching system configs." + }, + "401": { + "description": "Unauthorized" + } + }, + "summary": "Retrieve system config facets", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/system/{system}": { + "get": { + "description": "Returns a single system (template) config identified by its `virtual_path` or\n`lookup_key`. The `system` parameter value is URL-decoded before lookup, so\npath segments with special characters may be passed URL-encoded.\n\nSystem configs are filesystem-backed templates and are readable by any\nauthenticated caller regardless of team or user ownership. Returns 404 when no\nsystem config matches the given identifier.\n", + "operationId": "get_api_v1_config_system__system", + "parameters": [ + { + "description": "Identifier of the system config to retrieve — either its `virtual_path` or its `lookup_key`. May be URL-encoded.", + "example": "string", + "in": "path", + "name": "system", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Config" + } + } + }, + "description": "The requested system config, including its current version and all metadata fields." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Config not found" + } + }, + "summary": "Retrieve a system config", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/system/{system}/clone": { + "post": { + "description": "Creates a copy of a system (template) config and transfers ownership to a team\nor user. All dependencies bundled with the source config are cloned alongside it.\nResponds with HTTP 201 and the newly created config on success.\n\nYou must specify exactly one destination owner via `team` or `user`. Callers\nauthenticated as an app (developer portal) may omit the owner — the clone is\nthen scoped to the system owner automatically.\n\nUse `virtual_path` and `lookup_key` to override the corresponding fields on the\nclone; omitting them carries the values from the source.\n", + "operationId": "post_api_v1_config_system__system_clone", + "parameters": [ + { + "description": "Identifier of the source system config — either its `virtual_path` or its `lookup_key`.", + "example": "string", + "in": "path", + "name": "system", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "lookup_key": "string", + "org": "string", + "team": "string", + "user": "string", + "virtual_path": "string" + }, + "properties": { + "lookup_key": { + "description": "Override the `lookup_key` on the cloned config. When omitted, the source value is used.", + "example": "string", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) to scope the clone to. When set, must match the authenticated viewer's org.", + "example": "string", + "type": "string" + }, + "team": { + "description": "Team ID (`tea_...`) that will own the cloned config. Required unless `user` is provided or the caller is app-scoped.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) that will own the cloned config. Required unless `team` is provided or the caller is app-scoped.", + "example": "string", + "type": "string" + }, + "virtual_path": { + "description": "Override the `virtual_path` on the cloned config. When omitted, the source value is used.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Config" + } + } + }, + "description": "The newly created config, including all cloned fields and its assigned ID." + }, + "400": { + "description": "Bad request - owner required" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Source config not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Clone a system config", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/validate": { + "post": { + "description": "Validates raw config content against the schema for a given config kind\nwithout saving anything. Returns a structured result indicating whether the\ncontent is valid and, if not, a list of error messages.\n\nUse this endpoint to give users early feedback before calling create or\nupdate. The owner context is used for any kind-specific validation rules that\nare owner-aware; provide the same owner you intend to use on the write call.\n\nRequires app scope.\n", + "operationId": "post_api_v1_config_validate", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "data": {}, + "data_encoding": "string", + "kind": "string", + "mime_type": "application/json", + "raw_content": "string", + "team": "string", + "user": "string" + }, + "properties": { + "agent": { + "description": "Agent ID (`agt_...`) that would own the config. Used for owner-aware validation rules. Mutually exclusive with `team` and `user`.", + "example": "string", + "type": "string" + }, + "data": { + "description": "Optional metadata used by kind-specific validation. File and Image configs require `data.name` when validating direct binary content.", + "example": {}, + "type": "object" + }, + "data_encoding": { + "description": "Encoding of `raw_content`. Omit or set `\"raw\"` for literal content; set `\"base64\"` when sending binary content such as images or PDFs in JSON.", + "example": "string", + "type": "string" + }, + "kind": { + "description": "Config kind whose schema the content is validated against, e.g. `\"Agent\"` or `\"APITool\"`.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of `raw_content`, e.g. `\"application/x-yaml\"` or `\"application/json\"`. Used to parse the content before validation.", + "example": "application/json", + "type": "string" + }, + "raw_content": { + "description": "Raw content bytes to validate. Parsed according to `mime_type` before schema validation.", + "example": "string", + "type": "string" + }, + "team": { + "description": "Team ID (`team_...`) that would own the config. Used for owner-aware validation rules. Mutually exclusive with `user` and `agent`.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) that would own the config. Used for owner-aware validation rules. Mutually exclusive with `team` and `agent`.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind", + "raw_content", + "mime_type" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationResult" + } + } + }, + "description": "Validation outcome. Always HTTP 200; check the `valid` field to determine success. Includes `errors` when `valid` is `false`." + }, + "400": { + "description": "Bad request - owner required" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + } + }, + "summary": "Validate config content", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/{config}": { + "delete": { + "description": "Permanently deletes a config and all its associated versions. This action is\nirreversible. To soft-delete a config while retaining its history, use the\narchive endpoint instead.\n\nThe config may be addressed by its ID (`cfg_...`), `virtual_path`, or\n`lookup_key`. When addressing by `lookup_key` or `virtual_path`, you must\nsupply exactly one owner selector (`team`, `user`, `agent`, or `system`);\npassing an owner selector when addressing by ID returns 422.\n\nReturns 204 No Content on success. Requires app scope. The viewer must have\nmodify rights on the config.\n", + "operationId": "delete_api_v1_config__config", + "parameters": [ + { + "description": "Config identifier. Accepts a config ID (`cfg_...`), a `virtual_path`, or a `lookup_key`. URL-encode `virtual_path` values that contain slashes.", + "example": "string", + "in": "path", + "name": "config", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty body. HTTP 204 indicates the config and all its versions were permanently deleted." + }, + "400": { + "description": "Bad request - owner required" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Config not found" + }, + "409": { + "description": "Conflict - config is in use by an active workflow run" + }, + "422": { + "description": "Validation failed - owner selector not allowed when addressing a config by id" + } + }, + "summary": "Delete a config", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns a single config identified by its ID, `virtual_path`, or\n`lookup_key`. The config object includes its current version metadata but\nnot the raw content bytes; use the content endpoint to fetch the raw content.\n\nWhen addressing by `lookup_key` or `virtual_path`, you must supply exactly\none owner selector (`team`, `user`, `agent`, or `system`). Passing an owner\nselector when addressing by ID (`cfg_...`) returns 422. Both `not_found`\nand `forbidden` outcomes are surfaced as 404 to avoid leaking config\nexistence.\n\nRequires app scope.\n", + "operationId": "get_api_v1_config__config", + "parameters": [ + { + "description": "Config identifier. Accepts a config ID (`cfg_...`), a `virtual_path`, or a `lookup_key`. URL-encode `virtual_path` values that contain slashes.", + "example": "string", + "in": "path", + "name": "config", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Team ID (`team_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Agent ID (`agt_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "in": "query", + "name": "agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Set `true` to resolve a system-owned config by `virtual_path` or `lookup_key`. Requires a privileged viewer (developer or all-powerful) or an org admin.", + "example": true, + "in": "query", + "name": "system", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Organization ID (`org_...`) to narrow the lookup to configs belonging to that org.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Config" + } + } + }, + "description": "The requested config object." + }, + "400": { + "description": "Bad request - owner required" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Config not found" + }, + "422": { + "description": "Validation failed - owner selector not allowed when addressing a config by id" + } + }, + "summary": "Retrieve a config", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "patch": { + "description": "Updates an existing config. When `raw_content` is provided, a new version is\ncreated and becomes the current version. When `raw_content` is omitted, only\nmetadata fields (`virtual_path`, `lookup_key`, `relative_path`,\n`parent_solution`) are updated without creating a new version.\n\nUse `expected_version` for optimistic concurrency control: if the config's\ncurrent version number does not match the supplied value the request returns\n409. This prevents overwriting concurrent edits.\n\nThe config may be addressed by its ID (`cfg_...`), `virtual_path`, or\n`lookup_key`. When addressing by `lookup_key` or `virtual_path`, you must\nsupply exactly one owner selector (`team`, `user`, `agent`, or `system`).\nBoth `not_found` and `forbidden` outcomes are surfaced as 404.\n\nRequires app scope. The viewer must have modify rights on the config.\n", + "operationId": "patch_api_v1_config__config", + "parameters": [ + { + "description": "Config identifier. Accepts a config ID (`cfg_...`), a `virtual_path`, or a `lookup_key`. URL-encode `virtual_path` values that contain slashes.", + "example": "string", + "in": "path", + "name": "config", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "change_description": "An example description.", + "data": {}, + "data_encoding": "string", + "expected_version": 1, + "lookup_key": "string", + "mime_type": "application/json", + "org": "string", + "parent_solution": "string", + "raw_content": "string", + "relative_path": "string", + "system": true, + "team": "string", + "user": "string", + "virtual_path": "string" + }, + "properties": { + "agent": { + "description": "Agent ID (`agt_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "type": "string" + }, + "change_description": { + "description": "Human-readable description of this update, stored on the new version record.", + "example": "An example description.", + "type": "string" + }, + "data": { + "description": "Arbitrary key-value metadata to store on the new version alongside the content.", + "example": {}, + "type": "object" + }, + "data_encoding": { + "description": "Encoding of `raw_content`. Omit or set `\"raw\"` for literal content; set `\"base64\"` when sending binary content such as images or PDFs in JSON.", + "example": "string", + "type": "string" + }, + "expected_version": { + "description": "Version number the caller expects to be current. If the config's actual current version does not match, the request returns 409 to signal a concurrent modification. Omit to skip optimistic locking.", + "example": 1, + "type": "integer" + }, + "lookup_key": { + "description": "New `lookup_key` for the config. Updates the key without creating a new version when `raw_content` is omitted.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of `raw_content`, e.g. `\"application/x-yaml\"` or `\"application/json\"`. Defaults to the existing MIME type when `raw_content` is provided without this field.", + "example": "application/json", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) to narrow the lookup to configs belonging to that org.", + "example": "string", + "type": "string" + }, + "parent_solution": { + "description": "Solution config ID (`cfg_...`) to set as the config's parent solution provenance. Clears the value when set to an empty string.", + "example": "string", + "type": "string" + }, + "raw_content": { + "description": "New raw content bytes for the config. When provided, a new version is created. Omit to perform a metadata-only update without incrementing the version.", + "example": "string", + "type": "string" + }, + "relative_path": { + "description": "Updated path of this config within its parent bundle. Only meaningful when the config has a `parent`.", + "example": "string", + "type": "string" + }, + "system": { + "description": "Set `true` to resolve a system-owned config by `virtual_path` or `lookup_key`. Requires a privileged viewer (developer or all-powerful) or an org admin.", + "example": true, + "type": "boolean" + }, + "team": { + "description": "Team ID (`team_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "type": "string" + }, + "virtual_path": { + "description": "New `virtual_path` for the config. Updates the path without creating a new version when `raw_content` is omitted.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Config" + } + } + }, + "description": "The config reflecting the applied update." + }, + "400": { + "description": "Bad request - owner required" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Config not found" + }, + "409": { + "description": "Conflict - config version changed" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Update a config", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/{config}/archive": { + "post": { + "description": "Soft-deletes a config by marking it as archived. Archived configs are hidden\nfrom list and show endpoints but are not permanently removed; use the\nunarchive endpoint to restore one, or the delete endpoint for permanent\nremoval.\n\nThe config may be addressed by its ID (`cfg_...`), `virtual_path`, or\n`lookup_key`. When addressing by `lookup_key` or `virtual_path`, you must\nsupply exactly one owner selector (`team`, `user`, `agent`, or `system`);\npassing an owner selector when addressing by ID returns 422.\n\nRequires app scope. The viewer must have modify rights on the config.\n", + "operationId": "post_api_v1_config__config_archive", + "parameters": [ + { + "description": "Config identifier. Accepts a config ID (`cfg_...`), a `virtual_path`, or a `lookup_key`. `virtual_path` values should be URL-encoded if they contain slashes.", + "example": "string", + "in": "path", + "name": "config", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "org": "string", + "system": true, + "team": "string", + "user": "string" + }, + "properties": { + "agent": { + "description": "Agent ID (`agt_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) to narrow the lookup to configs belonging to that org. Useful when the viewer has access to multiple orgs.", + "example": "string", + "type": "string" + }, + "system": { + "description": "Set `true` to resolve a system-owned config by `virtual_path` or `lookup_key`. Requires a privileged viewer (developer or all-powerful) or an org admin.", + "example": true, + "type": "boolean" + }, + "team": { + "description": "Team ID (`team_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Config" + } + } + }, + "description": "The config in its newly archived state." + }, + "400": { + "description": "Bad request - owner required" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Config not found" + }, + "422": { + "description": "Validation failed - owner selector not allowed when addressing a config by id" + } + }, + "summary": "Archive a config", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/{config}/change_owner": { + "post": { + "description": "Transfers a config to a new owner (`team`, `user`, `agent`, or `system`).\nExactly one of the new-owner selectors must be provided. The config must be\naddressed by its ID (`cfg_...` or UUID); `virtual_path` and `lookup_key`\nare not accepted to avoid ambiguity — look up the ID first if needed.\n\nFor non-system targets the new owner's org is derived automatically from the\ntarget entity; supplying `org` in that case returns 422. For `system:true`\ntargets, `org` controls the resulting org scope: omit to keep the existing\n`org_id`, supply a value to set a specific org, or pass `null`/blank to make\nthe config app-level (operator viewers only).\n\nOperator viewers (developer credentials or all-powerful viewers) may transfer\nto any owner. All other viewers are restricted to owners they can themselves\naccess (team membership, user identity, agent scope, or `system` with the\nappropriate privilege).\n\nRequires app scope. The viewer must have modify rights on the config.\n", + "operationId": "post_api_v1_config__config_change_owner", + "parameters": [ + { + "description": "Config ID in id-form: `cfg_...` or a UUID. `lookup_key` and `virtual_path` are not accepted — retrieve the config ID first if you only have a path.", + "example": "string", + "in": "path", + "name": "config", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "org": "string", + "system": true, + "team": "string", + "user": "string" + }, + "properties": { + "agent": { + "description": "New owner: Agent ID (`agt_...`). Mutually exclusive with `team`, `user`, and `system`.", + "example": "string", + "type": "string" + }, + "org": { + "description": "Only valid when `system:true`. Omit to keep the config's existing `org_id`; supply an org ID (`org_...`) to set a specific org scope; pass blank or `null` to make the config app-level (operator viewers only). Setting `org` for `team`, `user`, or `agent` targets returns 422.", + "example": "string", + "type": "string" + }, + "system": { + "description": "Set `true` to transfer to system ownership (app-level or org-scoped). Requires a privileged viewer. Mutually exclusive with `team`, `user`, and `agent`.", + "example": true, + "type": "boolean" + }, + "team": { + "description": "New owner: Team ID (`team_...`). Mutually exclusive with `user`, `agent`, and `system`.", + "example": "string", + "type": "string" + }, + "user": { + "description": "New owner: User ID (`usr_...`). Mutually exclusive with `team`, `agent`, and `system`.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Config" + } + } + }, + "description": "The config reflecting its new ownership." + }, + "400": { + "description": "Bad request - new owner required" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Config not found (also returned when viewer cannot modify it)" + }, + "422": { + "description": "Validation failed (owner conflict, unique constraint, id-form required)" + } + }, + "summary": "Transfer ownership of a config", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/{config}/content": { + "get": { + "description": "Returns the raw byte content of a config's current version. The response\n`Content-Type` header reflects the config's stored MIME type unless a\n`format` conversion is requested.\n\nPass `format: \"yaml\"` or `format: \"json\"` to convert between YAML and JSON\non the fly. Conversion is only supported between these two formats; requesting\na conversion that is not possible returns 400.\n\nBy default, `virtual_path` and other platform-injected protected fields are\nembedded in the returned content. Set `inject_protected_fields: false` to\nreturn the stored raw bytes exactly as written.\n\nThe config may be addressed by ID (`cfg_...`), `virtual_path`, or\n`lookup_key`. When addressing by `lookup_key` or `virtual_path`, exactly one\nowner selector (`team`, `user`, `agent`, or `system`) is required.\n", + "operationId": "get_api_v1_config__config_content", + "parameters": [ + { + "description": "Config identifier. Accepts a config ID (`cfg_...`), a `virtual_path`, or a `lookup_key`. URL-encode `virtual_path` values that contain slashes.", + "example": "string", + "in": "path", + "name": "config", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Team ID (`team_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Agent ID (`agt_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "in": "query", + "name": "agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Set `true` to resolve a system-owned config by `virtual_path` or `lookup_key`. Requires a privileged viewer (developer or all-powerful) or an org admin.", + "example": true, + "in": "query", + "name": "system", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Organization ID (`org_...`) to narrow the lookup to configs belonging to that org.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Output format for content conversion. One of `\"yaml\"` or `\"json\"`. Omit to return the content in its stored format. Returns 400 if conversion is not possible.", + "example": "string", + "in": "query", + "name": "format", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Whether to inject platform-managed protected fields (such as `virtual_path`) into the returned content. Defaults to `true`. Set to `false` to receive the raw stored bytes.", + "example": true, + "in": "query", + "name": "inject_protected_fields", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "*/*": { + "schema": { + "format": "binary", + "type": "string" + } + } + }, + "description": "Raw config content in the stored or requested format." + }, + "400": { + "description": "Bad request - owner required or conversion not possible" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Config not found" + }, + "422": { + "description": "Validation failed - owner selector not allowed when addressing a config by id" + } + }, + "summary": "Retrieve a config's raw content", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/{config}/unarchive": { + "post": { + "description": "Restores a previously archived config, making it visible again in list and\nshow responses. The config's content and version history are unchanged.\n\nThe config may be addressed by its ID (`cfg_...`), `virtual_path`, or\n`lookup_key`. When addressing by `lookup_key` or `virtual_path`, you must\nsupply exactly one owner selector (`team`, `user`, `agent`, or `system`);\npassing an owner selector when addressing by ID returns 422.\n\nRequires app scope. The viewer must have modify rights on the config.\n", + "operationId": "post_api_v1_config__config_unarchive", + "parameters": [ + { + "description": "Config identifier. Accepts a config ID (`cfg_...`), a `virtual_path`, or a `lookup_key`. URL-encode `virtual_path` values that contain slashes.", + "example": "string", + "in": "path", + "name": "config", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "org": "string", + "system": true, + "team": "string", + "user": "string" + }, + "properties": { + "agent": { + "description": "Agent ID (`agt_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) to narrow the lookup to configs belonging to that org.", + "example": "string", + "type": "string" + }, + "system": { + "description": "Set `true` to resolve a system-owned config by `virtual_path` or `lookup_key`. Requires a privileged viewer (developer or all-powerful) or an org admin.", + "example": true, + "type": "boolean" + }, + "team": { + "description": "Team ID (`team_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Config" + } + } + }, + "description": "The config in its newly restored (active) state." + }, + "400": { + "description": "Bad request - owner required" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Config not found" + }, + "422": { + "description": "Validation failed - owner selector not allowed when addressing a config by id" + } + }, + "summary": "Unarchive a config", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/config/{config}/versions": { + "get": { + "description": "Returns all versions of a config in the order they were created, most recent\nfirst. Each version includes its version number, content metadata, and change\ndescription. The raw content bytes for a specific version are not included;\nuse the content endpoint to fetch them.\n\nThe config may be addressed by its ID (`cfg_...`), `virtual_path`, or\n`lookup_key`. When addressing by `lookup_key` or `virtual_path`, you must\nsupply exactly one owner selector (`team`, `user`, `agent`, or `system`).\nBoth `not_found` and `forbidden` outcomes are surfaced as 404.\n\nRequires app scope.\n", + "operationId": "get_api_v1_config__config_versions", + "parameters": [ + { + "description": "Config identifier. Accepts a config ID (`cfg_...`), a `virtual_path`, or a `lookup_key`. URL-encode `virtual_path` values that contain slashes.", + "example": "string", + "in": "path", + "name": "config", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Team ID (`team_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Agent ID (`agt_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`.", + "example": "string", + "in": "query", + "name": "agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Set `true` to resolve a system-owned config by `virtual_path` or `lookup_key`. Requires a privileged viewer (developer or all-powerful) or an org admin.", + "example": true, + "in": "query", + "name": "system", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Organization ID (`org_...`) to narrow the lookup to configs belonging to that org.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "The config's complete version history.", + "example": { + "versions": [ + { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + } + ] + }, + "properties": { + "versions": { + "description": "Array of version objects ordered from most recent to oldest.", + "example": [ + { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + } + ], + "items": { + "description": "A single immutable snapshot of a config's content, created each time the config is saved.", + "example": { + "change_description": "An example description.", + "content_hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "created_at": "2024-01-01T00:00:00Z", + "data": {}, + "id": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution_config_version": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "version_number": 1 + }, + "properties": { + "change_description": { + "description": "Human-readable summary of what changed in this version, as provided by the author. `null` if no description was supplied.", + "example": "An example description.", + "type": "string" + }, + "content_hash": { + "description": "SHA-256 digest of the raw config content encoded as `sha256:`. Uses the same algorithm as the CLI `computeContentHash` helper. `null` for versions created before this field was introduced.", + "example": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "type": "string" + }, + "created_at": { + "description": "When this config version was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "data": { + "description": "Arbitrary structured metadata stored alongside this version. `null` when no extra data was provided.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Config version ID (`cfv_...`).", + "example": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this config version. `null` for personal configs.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Sandbox ID (`sbx_...`) this version was saved under. `null` for production configs.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution_config_version": { + "description": "Config version ID (`cfv_...`) for the Solution version this config version was installed from. `null` for standalone configs and legacy rows.", + "example": "cfv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "version_number": { + "description": "Monotonically increasing integer identifying this version within the config. Starts at 1.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "version_number" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "versions" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Bad request - owner required" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Config not found" + }, + "422": { + "description": "Validation failed - owner selector not allowed when addressing a config by id" + } + }, + "summary": "List a config's version history", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/custom_objects": { + "get": { + "description": "Returns a paginated list of custom objects visible to the authenticated\nviewer, ordered by creation time descending. Results span all ownership\ntypes (team-owned, user-owned, agent-owned, and system-owned) that the\nviewer has access to.\n\nFilter by schema type with `type` (preferred) or the legacy alias\n`schema_key`. Use the `row_key` param to perform an exact-match partition\nlookup. You may additionally supply `sort_key` to narrow within that\npartition — `sort_key` requires `row_key` and the request returns 400 if\n`sort_key` is provided alone. Owner filters (`team`, `user`, `agent`,\n`org`) are additive: each accepts an array of IDs (or a single ID, which\nis wrapped) and returns objects matching any of the supplied values.\n\nWhen `query` is supplied, results are ranked by full-text relevance\n(descending `ts_rank`) rather than creation time. The legacy `search`\nparam performs a case-insensitive substring match and is retained for\ndeveloper-namespace clients.\n", + "operationId": "get_api_v1_custom_objects", + "parameters": [ + { + "description": "Schema type identifier (`lookup_key`) to filter by. Only objects of this type are returned. Alias of `schema_key`; either name is accepted.", + "example": "string", + "in": "query", + "name": "type", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Legacy alias for `type`. Prefer `type` on new clients. When both are supplied, `type` wins.", + "example": "string", + "in": "query", + "name": "schema_key", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Exact `row_key` value to match. When supplied, only objects with this partition key are returned.", + "example": "string", + "in": "query", + "name": "row_key", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "One or more `sort_key` values to match within the `row_key` partition. Requires `row_key` to be set.", + "example": [ + "string" + ], + "in": "query", + "name": "sort_key", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "One or more team IDs (`team_...`) to filter by owning team. Returns objects owned by any of the supplied teams.", + "example": [ + "string" + ], + "in": "query", + "name": "team", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "One or more user IDs (`user_...`) to filter by owning user. Returns objects owned by any of the supplied users.", + "example": [ + "string" + ], + "in": "query", + "name": "user", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "One or more agent IDs to filter by owning agent. Returns objects owned by any of the supplied agents.", + "example": [ + "string" + ], + "in": "query", + "name": "agent", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "One or more organization IDs (`org_...`) to filter by. Typically used by admins to query system-owned objects in a specific org.", + "example": [ + "string" + ], + "in": "query", + "name": "org", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Full-text search string matched against the schema's configured search fields. When supplied, results are ordered by relevance score descending instead of creation time descending.", + "example": "string", + "in": "query", + "name": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Case-insensitive substring search applied across the schema type and serialized field values. Deprecated — prefer `query` for full-text search. Retained for developer-namespace clients.", + "example": "string", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Page number to retrieve (1-indexed). Defaults to `1`.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of objects per page. Defaults to `25`; maximum is `100`.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomObjectListResponse" + } + } + }, + "description": "Paginated list of custom objects matching the supplied filters." + }, + "400": { + "description": "Invalid filter combination (e.g. sort_key without row_key)" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + } + }, + "summary": "List custom objects", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new custom object of the given schema type and returns the\npersisted object. The caller must be authenticated and authorized to create\nobjects of the specified type.\n\nIdentify the schema with `type` (preferred), or the legacy aliases\n`schema_key` (lookup key) / `config` (config ID). Exactly one identifier is\nrequired; when more than one is supplied, `type` wins over `schema_key`,\nwhich wins over `config`.\n\nOwner resolution follows a priority order: if `team` is supplied the object\nis team-owned; if `user` is supplied it is owned by that user; if `agent` is\nsupplied it is agent-owned; otherwise the object is owned by the authenticated\nuser. Pass `system: true` explicitly to force system ownership — this requires\nelevated API credentials and returns 403 if the caller lacks permission.\n\nIf the schema declares a `row_key` (and optionally a `sort_key`), you may\npass `upsert: true` to update an existing object at that key instead of\nreceiving a 409 Conflict. The response status is `200` on an update and\n`201` on a new create.\n", + "operationId": "post_api_v1_custom_objects", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "agent": "string", + "config": "string", + "fields": {}, + "org": "string", + "schema_key": "string", + "system": true, + "team": "string", + "type": "string", + "upsert": true, + "user": "string" + }, + "properties": { + "acl": { + "description": "Access control list for the custom object. Supports explicit `read` and `write` grants to users, teams, organizations, organization roles, agents, or everyone.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "agent": { + "description": "Agent user ID to set as the object owner. Used when neither `team` nor `user` is supplied.", + "example": "string", + "type": "string" + }, + "config": { + "description": "Config ID (`cfg_...`) that resolves to the target schema. Provide one of `type`, `schema_key`, or `config`.", + "example": "string", + "type": "string" + }, + "fields": { + "description": "Key-value map of field values for the new object. Must conform to the schema's field definitions. Omit to create an object with all fields at their default or null values.", + "example": {}, + "type": "object" + }, + "org": { + "description": "Organization ID (`org_...`) to associate with the object. Typically required for system-owned objects.", + "example": "string", + "type": "string" + }, + "schema_key": { + "description": "Legacy alias for `type` (schema `lookup_key`). Prefer `type` on new clients. Provide one of `type`, `schema_key`, or `config`.", + "example": "string", + "type": "string" + }, + "system": { + "description": "When `true`, creates a system-owned object with no team, user, or agent owner. Requires elevated API credentials; returns 403 if the caller lacks permission.", + "example": true, + "type": "boolean" + }, + "team": { + "description": "Team ID (`team_...`) to set as the object owner. When supplied, takes priority over `user` and `agent`.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Schema type identifier (`lookup_key`) that defines the object's shape and validation rules. Preferred over the legacy `schema_key` / `config` aliases.", + "example": "string", + "type": "string" + }, + "upsert": { + "description": "When `true` and the schema declares a `row_key`, updates the existing object at that key for the same owner instead of returning 409 Conflict. Returns HTTP 200 on update and 201 on create.", + "example": true, + "type": "boolean" + }, + "user": { + "description": "User ID (`user_...`) to set as the object owner. Used when neither `team` nor a higher-priority owner is set.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomObject" + } + } + }, + "description": "The created (or upserted) custom object." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Conflict - an object already occupies this row_key" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create a custom object", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/custom_objects/{object}": { + "delete": { + "description": "Permanently deletes the custom object identified by `object`. The caller\nmust be authenticated and have permission to delete the object.\n\nOn success, returns a confirmation payload containing the deleted object's\nID so callers can confirm the deletion without a follow-up fetch.\nAttempting to delete an object that does not exist or has already been\ndeleted returns 404.\n", + "operationId": "delete_api_v1_custom_objects__object", + "parameters": [ + { + "description": "Custom object ID (`cobj_...`) of the object to delete.", + "example": "string", + "in": "path", + "name": "object", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Confirmation that the custom object was deleted.", + "example": { + "deleted": true, + "id": "string" + }, + "properties": { + "deleted": { + "description": "Always `true` when the deletion succeeds.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "ID of the deleted custom object (`cobj_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "deleted", + "id" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not found" + } + }, + "summary": "Delete a custom object", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns a single custom object identified by its ID. The authenticated viewer\nmust have visibility access to the object.\n\nReturns 404 if the object does not exist, has been deleted, or is not\nvisible to the viewer.\n", + "operationId": "get_api_v1_custom_objects__object", + "parameters": [ + { + "description": "Schema type identifier (`lookup_key`) of the object. Optional; used for routing context only.", + "example": "string", + "in": "query", + "name": "type", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Custom object ID (`cobj_...`) to retrieve.", + "example": "string", + "in": "path", + "name": "object", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomObject" + } + } + }, + "description": "The requested custom object." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not found" + } + }, + "summary": "Retrieve a custom object", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "put": { + "description": "Updates the fields of an existing custom object and returns the updated\nobject along with its new version number. The authenticated viewer must have\npermission to modify the object.\n\nYou may supply `fields` (a full or partial key-value map to merge into the\nobject), `field_ops` (granular array operations per field), `acl`, or any\ncompatible combination. The same field name must not appear in both\n`fields` and `field_ops`, which returns 422. Returns 404 if the object does\nnot exist or has been deleted.\n", + "operationId": "put_api_v1_custom_objects__object", + "parameters": [ + { + "description": "Custom object ID (`cobj_...`) to update.", + "example": "string", + "in": "path", + "name": "object", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "field_ops": {}, + "fields": {}, + "type": "string" + }, + "properties": { + "acl": { + "description": "Updated access control list. Supports full replacement via `grants` or targeted `add`/`remove` operations.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "field_ops": { + "description": "Granular array operations to apply per field (e.g. append, prepend, remove). A field must not appear in both `fields` and `field_ops`.", + "example": {}, + "type": "object" + }, + "fields": { + "description": "Key-value map of field values to merge into the object. Only the supplied keys are affected.", + "example": {}, + "type": "object" + }, + "type": { + "description": "Schema type identifier (`lookup_key`) of the object. Optional; used for routing context only.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "The updated custom object and its new version metadata.", + "example": { + "data": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "created_at": "2024-01-01T00:00:00Z", + "fields": { + "key": "value" + }, + "id": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "row_key": "string", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "schema_type": "contact", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + }, + "meta": {} + }, + "properties": { + "data": { + "description": "The custom object after the update has been applied.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "created_at": "2024-01-01T00:00:00Z", + "fields": { + "key": "value" + }, + "id": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "row_key": "string", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "schema_type": "contact", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + }, + "properties": { + "acl": { + "description": "Access control list governing read and write access to this custom object. Only returned to resource owners and privileged or organization-admin viewers; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "created_at": { + "description": "When the custom object was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "fields": { + "description": "Map of field names to their current values as defined by the object's schema type.", + "example": { + "key": "value" + }, + "type": "object" + }, + "id": { + "description": "Unique identifier for the custom object (`cobj_...`).", + "example": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org": { + "description": "ID of the organization this object belongs to (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "row_key": { + "description": "An optional stable key used to identify this object by a caller-controlled string rather than its generated ID. `null` if not set.", + "example": "string", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this object is scoped to (`dsb_...`). `null` for production objects.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "schema_type": { + "description": "The lookup key of the schema type that defines this object's field structure. `null` if the schema type has not been set.", + "example": "contact", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this object (`tem_...`). `null` if the object is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the custom object was last modified (ISO 8601). `null` if the object has never been updated after creation.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this object (`usr_...`). `null` if the object is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "version": { + "description": "Optimistic concurrency version of the object. Increments with each successful update; pass this value in write operations to detect conflicting changes.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "meta": { + "description": "Version metadata for the updated object.", + "example": {}, + "type": "object" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Update a custom object", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/extractions": { + "post": { + "description": "Records a text-extraction job for a document (`file`) or a URL (`url` + `mode`).\nThe job is owner-scoped and tagged with the caller-supplied `destination`\nnamespace, **without** committing knowledge to an agent (no embeddings, no\nagent attach).\n\nExactly one of `file` or (`url` + `mode`) is required.\n\nDocument extraction (`file`) runs synchronously: the response already\nreflects the final state (`done` with its output, or an error if extraction\ncouldn't complete), status `201`. URL extraction (`url` + `mode`) submits an\nasync crawl and returns immediately with state `running`, status `202` —\npoll `GET /extractions/:extraction` for its terminal state.\n", + "operationId": "post_api_v1_extractions", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "destination_kind": "config", + "destination_path": "string", + "file": "string", + "max_pages": 1, + "mode": "link", + "org": "string", + "url": "https://example.com" + }, + "properties": { + "agent": { + "description": "Owning agent (`agt_...`) — scopes the extraction and its outputs.", + "example": "string", + "type": "string" + }, + "destination_kind": { + "description": "Where outputs are written.", + "enum": [ + "config", + "storage" + ], + "example": "config", + "type": "string" + }, + "destination_path": { + "description": "Destination virtual_path prefix. Required for `destination_kind=config`, where it must name at least one path segment (`.` and `..` segments are dropped).", + "example": "string", + "type": "string" + }, + "file": { + "description": "Source file id (`fil_...`) for document extraction. Runs synchronously, so the source must be at most 10MB; larger files are rejected.", + "example": "string", + "type": "string" + }, + "max_pages": { + "description": "Crawl cap for `mode=site` — must be at least 1 (defaults to 100; `link` is always 1).", + "example": 1, + "type": "integer" + }, + "mode": { + "description": "Required with `url`. Document extraction is selected by `file` instead and takes no `mode` (its `kind` is `document`).", + "enum": [ + "link", + "site" + ], + "example": "link", + "type": "string" + }, + "org": { + "description": "Owning organization (`org_...`). Defaults to the viewer's org.", + "example": "string", + "type": "string" + }, + "url": { + "description": "Source URL for link/site extraction.", + "example": "https://example.com", + "type": "string" + } + }, + "required": [ + "destination_kind" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Extraction" + } + } + }, + "description": "The extraction job. Document extraction returns `201` with `state: \"done\"`; link/site extraction returns `202` with `state: \"running\"`." + }, + "404": { + "description": "File not found" + }, + "422": { + "description": "Invalid parameters; Unsupported content type" + }, + "502": { + "description": "Service unavailable" + } + }, + "summary": "Start an extraction", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/extractions/{extraction}": { + "get": { + "description": "Returns a single extraction job and its current state. Poll this endpoint after\nstarting an async (link/site) extraction until `state` is `done` or `failed`.\n\nAn extraction that exists but is not visible to the current viewer returns `404`\nrather than `403`, so the resource's existence is not revealed.\n", + "operationId": "get_api_v1_extractions__extraction", + "parameters": [ + { + "description": "Extraction ID (`ext_...`).", + "example": "string", + "in": "path", + "name": "extraction", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Extraction" + } + } + }, + "description": "The extraction job." + }, + "404": { + "description": "Extraction not found" + } + }, + "summary": "Retrieve an extraction", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/files": { + "post": { + "description": "Creates a new file from base64-encoded content and returns the resulting file object,\nincluding a signed download URL. Use this endpoint to store images, documents, or\nother binary assets that can then be referenced by agents, teams, or users.\n\nApp scope is derived from the authenticated viewer's bearer token or publishable key.\nYou may optionally associate the file with an organization, team, user, or agent by\npassing the corresponding ID. If no owner is specified and the viewer is a user, the\nfile is automatically attributed to that user.\n\nPass `share: true` to additionally mint a stable public URL for the file\n(returned as `share_url`), fetchable by anyone without authentication — for\nexample to embed an uploaded image in a GitHub PR body or other external\nmarkdown. The URL does not expire. Sharing is revoked by setting\n`share: false` on `PATCH /api/v1/files/:file` with the same credential\n(or `archastro update file --unshare`); re-enabling sharing\nreactivates previously issued URLs. Only image content types can be\nshared.\n\nReturns `422` when the `data` field is not valid base64, the changeset is\ninvalid, or `share` is requested for a non-image content type.\nReturns `403` when the request lacks the required app scope.\n", + "operationId": "post_api_v1_files", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "agent": "string", + "content_type": "application/json", + "data": "string", + "filename": "string", + "org": "string", + "share": true, + "team": "string", + "user": "string" + }, + "properties": { + "acl": { + "description": "Access control list for the file. Supports explicit `read` and `write` grants to users, teams, organizations, organization roles, agents, or everyone.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "agent": { + "description": "Agent ID (`agi_...`) to associate with this file. When provided, the file's organization is derived from the agent.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the file, e.g. `\"image/png\"` or `\"application/pdf\"`.", + "example": "application/json", + "type": "string" + }, + "data": { + "description": "Base64-encoded binary content of the file to upload.", + "example": "string", + "type": "string" + }, + "filename": { + "description": "Original filename including extension, e.g. `\"avatar.png\"`.", + "example": "string", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) to associate with this file. Optional; defaults to the viewer's organization when omitted.", + "example": "string", + "type": "string" + }, + "share": { + "description": "When `true`, marks the file publicly shareable and returns a stable, non-expiring `share_url` fetchable without authentication. Only image content types can be shared.", + "example": true, + "type": "boolean" + }, + "team": { + "description": "Team ID (`tem_...`) that owns this file. Takes precedence over `user` when both are provided.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) that owns this file. Defaults to the authenticated user when neither `user` nor `team` is specified.", + "example": "string", + "type": "string" + } + }, + "required": [ + "data", + "content_type", + "filename" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageFile" + } + } + }, + "description": "The newly created file, including a signed download URL." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "422": { + "description": "Validation failed or invalid base64" + } + }, + "summary": "Upload a file", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/files/{file}": { + "patch": { + "description": "Updates mutable fields of an existing file. Only the fields you supply are\nchanged; omitted fields retain their current values. The file's stored content\nand `content_type` cannot be changed after creation.\n\nThis endpoint is the companion to `share: true` on file upload: the same\ncredential that granted public sharing can revoke it here with `share: false`\n(or grant it later with `share: true`; only image content types can be\nshared, and re-enabling sharing reactivates any previously issued share\nURLs). App scope is derived from the authenticated viewer, matching upload.\n\nA file that exists but is not visible to the current viewer returns `404`\nrather than `403` to avoid revealing the file's existence.\n", + "operationId": "patch_api_v1_files__file", + "parameters": [ + { + "description": "File ID (`fil_...`) of the file to update.", + "example": "string", + "in": "path", + "name": "file", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "filename": "string", + "provider_metadata": { + "key": "value" + }, + "share": true + }, + "properties": { + "filename": { + "description": "New name for the file, including extension, e.g. `\"report_v2.pdf\"`. Omit to leave the current filename unchanged.", + "example": "string", + "type": "string" + }, + "provider_metadata": { + "description": "Arbitrary key-value map of provider-specific metadata to store alongside the file. Replaces the entire existing `provider_metadata` map. Omit to leave it unchanged.", + "example": { + "key": "value" + }, + "type": "object" + }, + "share": { + "description": "Set `true` to mark the file publicly shareable via its stable `share_url` (image content types only), or `false` to revoke public sharing. Re-enabling sharing reactivates any previously issued share URLs for the file. Omit to leave sharing unchanged.", + "example": true, + "type": "boolean" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageFile" + } + } + }, + "description": "The updated file, including a signed download URL." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "File not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Update a file", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/files/{file}/avatar": { + "get": { + "description": "Returns the raw image bytes for an agent's profile picture identified by `file`.\nThis endpoint is designed for integration partners (such as Slack) that fetch\navatar URLs via plain GET requests without bearer token support. Authorization\nis performed via a short, stable capability `token` rather than an HTTP header.\n\nThe `token` is an HMAC-based capability tied to the file ID. It does not expire,\nbut it is invalidated when the agent's profile picture is replaced or the agent is\ndeleted — shared caches may continue serving the old image until the\n`Cache-Control` max-age of one hour elapses. The endpoint never redirects to\na signed storage URL; bytes are served inline so behavior is consistent across\nstorage backends.\n\nAll failure modes — invalid file ID, invalid token, file not currently referenced\nas an agent avatar — return a uniform `404` to avoid acting as an existence oracle.\n", + "operationId": "get_api_v1_files__file_avatar", + "parameters": [ + { + "description": "File ID of the agent's profile picture (`fil_...`). Must be currently set as an agent's profile picture within the same app.", + "example": "string", + "in": "path", + "name": "file", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "HMAC capability token authorizing access to this specific file. Obtained from the avatar URL minted when the profile picture was set.", + "example": "string", + "in": "query", + "name": "token", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "*/*": { + "schema": { + "format": "binary", + "type": "string" + } + } + }, + "description": "Raw image bytes of the agent avatar, served with the file's original content type." + }, + "404": { + "description": "Not found" + } + }, + "summary": "Fetch an agent avatar image" + } + }, + "/api/v1/files/{file}/org_logo": { + "get": { + "description": "Returns the raw image bytes for an organization's logo identified by `file`.\nThis endpoint backs the `org_logo.url` field of catalog payloads (such as\n`GET /api/v1/solutions`), which anonymous consumers — the public marketplace's\npage cache, OpenGraph scrapers — may hold far longer than a signed storage URL\nlives. Authorization is performed via a short, stable capability `token` rather\nthan an HTTP header, so the URL never expires.\n\nThe `token` is an HMAC-based capability tied to the file ID. It does not expire,\nbut it is invalidated when the org's logo is replaced or removed — shared caches\nmay continue serving the old image until the `Cache-Control` max-age of one hour\nelapses. The endpoint never redirects to a signed storage URL; bytes are served\ninline so behavior is consistent across storage backends.\n\nAll failure modes — invalid file ID, invalid token, file not currently referenced\nas an org logo — return a uniform `404` to avoid acting as an existence oracle.\n", + "operationId": "get_api_v1_files__file_org_logo", + "parameters": [ + { + "description": "File ID of the org's logo (`fil_...`). Must be currently set as an organization's logo within the same app.", + "example": "string", + "in": "path", + "name": "file", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "HMAC capability token authorizing access to this specific file. Obtained from the `org_logo.url` minted when the logo was serialized.", + "example": "string", + "in": "query", + "name": "token", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "*/*": { + "schema": { + "format": "binary", + "type": "string" + } + } + }, + "description": "Raw image bytes of the org logo, served with the file's original content type." + }, + "404": { + "description": "Not found" + } + }, + "summary": "Fetch an org logo image" + } + }, + "/api/v1/files/{file}/share": { + "get": { + "description": "Returns the raw image bytes for a file that was explicitly shared for public\naccess, identified by `file`. This endpoint is designed for consumers that hold\na URL far longer than a signed storage URL lives — GitHub PR bodies (whose camo\nimage proxy re-fetches from the origin URL), wikis, and issue trackers — and\nfetch it via plain GET requests without bearer token support. Authorization is\nperformed via a short, stable capability `token` rather than an HTTP header.\n\nThe `token` is an HMAC-based capability tied to the file ID. It does not expire,\nbut it is invalidated when sharing is turned off for the file (`share: false` on\nthe file update endpoint) or the file is deleted — shared caches may continue\nserving the bytes until the `Cache-Control` max-age of one hour elapses. The\nendpoint never redirects to a signed storage URL; bytes are served inline so\nbehavior is consistent across storage backends. Only image content types are\nserved.\n\nAll failure modes — invalid file ID, invalid token, file not currently shared —\nreturn a uniform `404` to avoid acting as an existence oracle.\n", + "operationId": "get_api_v1_files__file_share", + "parameters": [ + { + "description": "File ID of the shared file (`fil_...`). The file must currently be marked as publicly shared.", + "example": "string", + "in": "path", + "name": "file", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "HMAC capability token authorizing access to this specific file. Obtained from the `share_url` returned when the file was uploaded with `share: true`.", + "example": "string", + "in": "query", + "name": "token", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "*/*": { + "schema": { + "format": "binary", + "type": "string" + } + } + }, + "description": "Raw image bytes of the shared file, served with the file's original content type." + }, + "404": { + "description": "Not found" + } + }, + "summary": "Fetch a publicly shared file" + } + }, + "/api/v1/installation_sources/{source}": { + "delete": { + "description": "Detaches and permanently deletes a source from an installation. This action\ncannot be undone; the source and its associated content will no longer be\navailable to the installation's agent.\n\nThis endpoint requires an app-scoped token. You may identify the target\nindirectly by providing only the `source` ID — the installation is resolved\nautomatically from the source record. Providing `installation` explicitly\nis also accepted and may be more efficient.\n", + "operationId": "delete_api_v1_installation_sources__source", + "parameters": [ + { + "description": "Source ID (`cso_...`) of the source to remove.", + "example": "string", + "in": "path", + "name": "source", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "No content" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Installation or source not found" + } + }, + "summary": "Remove a source from an installation", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/invites/accept": { + "post": { + "description": "Accepts an invite on behalf of the authenticated user and adds them to the\nassociated team or thread. The invite `key` is passed in the request body\nrather than the URL so it never appears in access logs, `Referer` headers,\nor error-reporter URL captures.\n\nThis endpoint requires an authenticated end-user session. S2S secret-key\ntokens and unauthenticated requests are rejected with `401`. If the\nauthenticated user is already a member of the invite's target, the request\nreturns `409`. Both per-IP and per-user rate limits apply; exceeding either\nreturns `429`.\n", + "operationId": "post_api_v1_invites_accept", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "key": "string" + }, + "properties": { + "key": { + "description": "Opaque invite key identifying the invite to accept. Obtained from an invite link or a previous invite creation response.", + "example": "string", + "type": "string" + } + }, + "required": [ + "key" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserInvite" + } + } + }, + "description": "The accepted invite, including its ID, key, metadata, optional thread scope, creator, and creation timestamp." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Invite not found" + }, + "409": { + "description": "Conflict" + }, + "422": { + "description": "Validation failed" + }, + "429": { + "description": "Too many requests" + } + }, + "summary": "Accept an invite", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/knowledge_documents": { + "get": { + "description": "Returns a paginated list of context documents visible to the authenticated\ncaller within the scoped app. Results are ordered by creation time\ndescending.\n\nUse `q` for a case-insensitive title prefix search. Use `source`,\n`installation`, or `agent` to narrow results to documents belonging to\nspecific sources, installations, or agents. Multiple values within each\nfilter are treated as OR conditions. Filters may be combined.\n\nThe response includes page-level metadata so you can navigate through\nlarge result sets without cursor tokens.\n", + "operationId": "get_api_v1_knowledge_documents", + "parameters": [ + { + "description": "Page number to return. Defaults to 1.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of documents per page. Defaults to 25.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Case-insensitive prefix filter applied to the document title.", + "example": "string", + "in": "query", + "name": "q", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return only documents belonging to these source IDs (`cso_...`). Multiple values are OR'd.", + "example": [ + "string" + ], + "in": "query", + "name": "source", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Return only documents belonging to these installation IDs. Multiple values are OR'd.", + "example": [ + "string" + ], + "in": "query", + "name": "installation", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Return only documents owned by these agent IDs. Multiple values are OR'd.", + "example": [ + "string" + ], + "in": "query", + "name": "agent", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Paginated list of context documents for the current page.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "content_hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "id": "cdo_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "source": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "total_lines": 1, + "total_size": 2048, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 1, + "total_entries": 1, + "total_pages": 1 + }, + "properties": { + "data": { + "description": "Array of context document objects for the current page.", + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "content_hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "id": "cdo_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "source": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "total_lines": 1, + "total_size": 2048, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A context document stored within a context source. Carries metadata and size information only; retrieve the full text content via the `/content` endpoint.\n", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "content_hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "id": "cdo_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "source": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "total_lines": 1, + "total_size": 2048, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this document (`agi_...`). `null` if owned by a user or team.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "content_hash": { + "description": "Lowercase-hex sha256 of the document's full text, covering content only — not `title` or `metadata`. Compare it against a hash of your local copy to decide whether the document needs re-ingesting, without fetching `/content`. `null` for documents ingested before this field existed; it is not backfilled.", + "example": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", + "type": "string" + }, + "created_at": { + "description": "When the document was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the backing storage file (`fil_...`) when the document is file-backed. `null` for inline documents.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "id": { + "description": "Context document ID (`cdo_...`).", + "example": "cdo_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the document. Shape varies by source type.", + "example": { + "key": "value" + }, + "type": "object" + }, + "source": { + "description": "ID of the context source this document belongs to (`cso_...`).", + "example": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this document (`tem_...`). `null` if owned by a user or agent.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "title": { + "description": "Human-readable display title of the document. `null` if no title has been set.", + "example": "Example Title", + "type": "string" + }, + "total_lines": { + "description": "Total number of lines in the document's text content. `0` if the document has no content.", + "example": 1, + "type": "integer" + }, + "total_size": { + "description": "Total byte size of the document's text content. `0` if the document has no content.", + "example": 2048, + "type": "integer" + }, + "updated_at": { + "description": "When the document was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this document (`usr_...`). `null` if owned by a team or agent.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "has_next": { + "description": "`true` if a subsequent page exists; `false` when this is the last page.", + "example": true, + "type": "boolean" + }, + "has_prev": { + "description": "`true` if a previous page exists; `false` when this is the first page.", + "example": true, + "type": "boolean" + }, + "page": { + "description": "The current page number.", + "example": 1, + "type": "integer" + }, + "page_size": { + "description": "Maximum number of documents returned per page.", + "example": 1, + "type": "integer" + }, + "total_entries": { + "description": "Total number of documents matching the applied filters across all pages.", + "example": 1, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages given the current `page_size`.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "data", + "page", + "page_size", + "total_entries", + "total_pages", + "has_next", + "has_prev" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + } + }, + "summary": "List context documents", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/knowledge_documents/{document}": { + "delete": { + "description": "Permanently deletes a context document and all of its associated chunk\nitems. This action is irreversible.\n\nThe backing storage file, if any, is not deleted — storage files can be\nshared across multiple documents and are cleaned up separately by the\nplatform's storage garbage collector. The caller must be authenticated\nand the request must be scoped to the app that owns the document.\n", + "operationId": "delete_api_v1_knowledge_documents__document", + "parameters": [ + { + "description": "Document ID (`cdo_...`) to delete.", + "example": "string", + "in": "path", + "name": "document", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty body. Returns HTTP 204 on success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Knowledge document not found" + } + }, + "summary": "Delete a context document", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns a single context document identified by its ID. The response\nincludes document metadata such as title, size, and ownership fields,\nbut not the document's text content. To read the full or partial content,\nuse the content endpoint.\n\nThe caller must be authenticated and the request must be scoped to the\napp that owns the document.\n", + "operationId": "get_api_v1_knowledge_documents__document", + "parameters": [ + { + "description": "Document ID (`cdo_...`) to retrieve.", + "example": "string", + "in": "path", + "name": "document", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContextDocument" + } + } + }, + "description": "The requested context document's metadata." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Knowledge document not found" + } + }, + "summary": "Retrieve a context document", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "patch": { + "description": "Replaces one document's content while preserving its document ID. The update\nruns asynchronously through the document's source pipeline: bytes are\nextracted and chunked, the prior chunks are replaced atomically, and fresh\ndocument and chunk embeddings are queued.\n\nSupply exactly one of `file` or `content`. Omitted `title` and `metadata`\nretain their current values. The response is an ingestion that can be polled\nat `GET /api/v1/knowledge_ingestions/:id` until it reaches `succeeded` or\n`failed`. `succeeded` means the replacement content and full-text indexes are\ncommitted and the embedding refresh is durably queued; vector computation\ncontinues in the retryable embedding worker.\n", + "operationId": "patch_api_v1_knowledge_documents__document", + "parameters": [ + { + "description": "Document ID (`cdo_...`) to update.", + "example": "string", + "in": "path", + "name": "document", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "content": { + "content_type": "application/json", + "data": "string", + "data_encoding": "string", + "filename": "string" + }, + "file": "string", + "metadata": { + "key": "value" + }, + "title": "Example Title" + }, + "properties": { + "content": { + "description": "Inline replacement bytes. Mutually exclusive with `file`.", + "example": { + "content_type": "application/json", + "data": "string", + "data_encoding": "string", + "filename": "string" + }, + "properties": { + "content_type": { + "description": "MIME type of the replacement content, such as `\"text/plain\"`.", + "example": "application/json", + "type": "string" + }, + "data": { + "description": "The replacement document bytes.", + "example": "string", + "type": "string" + }, + "data_encoding": { + "description": "Encoding of `data`: `\"raw\"` (default) or `\"base64\"`.", + "example": "string", + "type": "string" + }, + "filename": { + "description": "Original filename for the replacement content.", + "example": "string", + "type": "string" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "file": { + "description": "ID of an already-uploaded file (`fil_...`). Mutually exclusive with `content`.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Replacement metadata map. Omit to retain the current metadata.", + "example": { + "key": "value" + }, + "type": "object" + }, + "title": { + "description": "Replacement display title. Omit to retain the current title.", + "example": "Example Title", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContextIngestion" + } + } + }, + "description": "The ingestion performing the document update." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Knowledge document not found" + }, + "422": { + "description": "Invalid parameters" + }, + "429": { + "description": "Too many requests" + } + }, + "summary": "Update a context document", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/knowledge_documents/{document}/content": { + "get": { + "description": "Returns the full text of a context document, or a slice of it when\n`offset`, `limit`, and `unit` are supplied. Both file-backed and inline\ndocuments are supported; the response shape is the same in either case.\n\nWhen slicing, set `unit` to `\"lines\"` (default) or `\"bytes\"`. A line-based\nslice uses a 1-indexed `offset`; a byte-based slice uses a 0-indexed\n`offset`. If you omit `offset`, the full document text is returned and the\nslice-specific response fields (`unit`, `offset`, `limit`, `start_line`,\n`end_line`, `start_byte`, `end_byte`) are absent.\n\nThe caller must be authenticated and the request must be scoped to an app\nthat owns the document.\n", + "operationId": "get_api_v1_knowledge_documents__document_content", + "parameters": [ + { + "description": "Document ID (`cdo_...`) whose content to retrieve.", + "example": "string", + "in": "path", + "name": "document", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Starting position for a content slice. When `unit` is `\"lines\"`, this is a 1-indexed line number. When `unit` is `\"bytes\"`, this is a 0-indexed byte offset. Omit to return the full document.", + "example": 1, + "in": "query", + "name": "offset", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Maximum number of units to return when slicing. Defaults to 200 when `unit` is `\"lines\"` and 8192 when `unit` is `\"bytes\"`.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Unit to use for `offset` and `limit`. One of `\"lines\"` (default) or `\"bytes\"`.", + "example": "string", + "in": "query", + "name": "unit", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContextDocumentContent" + } + } + }, + "description": "The document's content, optionally sliced by offset and limit." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Knowledge document not found" + }, + "422": { + "description": "Invalid parameters; Failed to load document content" + } + }, + "summary": "Retrieve a context document's content", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/knowledge_ingestions/{ingestion}": { + "get": { + "description": "Returns the status, error details, and metadata for a knowledge ingestion.\nUse the ingestion ID returned by an asynchronous knowledge source or document\noperation. Inaccessible and unknown ingestions both return 404.\n", + "operationId": "get_api_v1_knowledge_ingestions__ingestion", + "parameters": [ + { + "description": "Knowledge ingestion ID (`cig_...`) to retrieve.", + "example": "string", + "in": "path", + "name": "ingestion", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContextIngestion" + } + } + }, + "description": "The requested knowledge ingestion." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Knowledge ingestion not found" + } + }, + "summary": "Retrieve a knowledge ingestion", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/knowledge_sources": { + "get": { + "description": "Returns a paginated list of knowledge sources visible to the authenticated caller.\nResults are ordered by creation time descending.\n\nUse the `type`, `installation`, `agent`, `org`, and `owner_scope` filters to narrow the\nresult set. Combine `owner_scope: \"system\"` with `org` to list org-level sources that\nhave no individual owner. Combine `owner_scope: \"individual\"` with `agent` to list\nsources owned by a specific agent.\n\nPagination is page-number based. The default page size is 25.\n", + "operationId": "get_api_v1_knowledge_sources", + "parameters": [ + { + "description": "Page number to retrieve. Defaults to 1.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of knowledge sources to return per page. Defaults to 25.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Filter sources whose type contains this string. Case-insensitive substring match.", + "example": "string", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Exact knowledge source type to filter by, e.g. `\"knowledge/documents\"`.", + "example": "string", + "in": "query", + "name": "type", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Installation ID (`ins_...`). Returns only sources associated with this installation.", + "example": "string", + "in": "query", + "name": "installation", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Agent ID (`agt_...`). Returns only sources owned by or associated with this agent.", + "example": "string", + "in": "query", + "name": "agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Organization ID (`org_...`). Returns only sources belonging to this organization. Combine with `owner_scope: \"system\"` to retrieve org-level system sources.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by ownership scope. One of `\"any\"` (default — returns all visible sources), `\"individual\"` (only sources owned by a user, team, or agent), or `\"system\"` (only sources with no individual owner, typically org-level).", + "example": "any", + "in": "query", + "name": "owner_scope", + "required": false, + "schema": { + "enum": [ + "any", + "individual", + "system" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Paginated list of knowledge sources.", + "example": { + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "context_installation": "cin_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "id": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_source": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "payload": { + "key": "value" + }, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "state": "active", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "gmail", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 1, + "total_entries": 1, + "total_pages": 1 + }, + "properties": { + "data": { + "description": "Array of knowledge source objects for the current page.", + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "context_installation": "cin_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "id": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_source": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "payload": { + "key": "value" + }, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "state": "active", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "gmail", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A knowledge source that ingests content into the knowledge base. Sources connect to external systems (e.g. Gmail, GitHub) and continuously or on-demand index items for search.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "context_installation": "cin_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "id": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_source": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "payload": { + "key": "value" + }, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "state": "active", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "gmail", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this source (`agt_...`). `null` if owned by a human user or team.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "context_installation": { + "description": "ID of the context installation that provisioned this source (`cin_...`). `null` when the source was created directly rather than through an installation.", + "example": "cin_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When this knowledge source was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Knowledge source ID (`cso_...`).", + "example": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this source. Useful for storing caller-defined labels or references.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization this source belongs to (`org_...`). `null` if not scoped to an org.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent_source": { + "description": "ID of the parent knowledge source (`cso_...`) when this source was derived from another. `null` for top-level sources.", + "example": "cso_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "payload": { + "description": "Type-specific configuration object. The keys depend on the source `type`; see the create endpoint for the expected shape per type.", + "example": { + "key": "value" + }, + "type": "object" + }, + "sandbox": { + "description": "ID of the developer sandbox this source is scoped to (`sbx_...`). `null` outside sandbox contexts.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "state": { + "description": "Current lifecycle state of the source. One of `\"active\"` (ingestion running normally) or `\"paused\"` (ingestion suspended).", + "example": "active", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this source (`tea_...`). `null` if owned by a user, agent, or org.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the chat thread this source is associated with (`thr_...`). `null` when not thread-scoped.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "type": { + "description": "Source type identifier (e.g. `\"gmail\"`, `\"github_activity\"`). Determines the shape of `payload` and the ingestion behavior.", + "example": "gmail", + "type": "string" + }, + "updated_at": { + "description": "When this knowledge source was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this source (`usr_...`). `null` if owned by a team, agent, or org.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "type", + "state" + ], + "type": "object" + }, + "type": "array" + }, + "has_next": { + "description": "`true` if a subsequent page exists, `false` if this is the last page.", + "example": true, + "type": "boolean" + }, + "has_prev": { + "description": "`true` if a previous page exists, `false` if this is the first page.", + "example": true, + "type": "boolean" + }, + "page": { + "description": "Current page number.", + "example": 1, + "type": "integer" + }, + "page_size": { + "description": "Number of results returned per page.", + "example": 1, + "type": "integer" + }, + "total_entries": { + "description": "Total number of knowledge sources matching the query across all pages.", + "example": 1, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages available.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "data", + "page", + "page_size", + "total_entries", + "total_pages", + "has_next", + "has_prev" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + } + }, + "summary": "List knowledge sources", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new knowledge source of the requested type and returns the created object.\n\nOnly types listed by `GET /api/v1/knowledge_sources/kinds` may be created through this\nendpoint. Other source types — such as `webhook/inbound`, `connectors/*/emails`, and\n`thread/messages` — are provisioned automatically by server-driven flows (webhook\nauto-provisioning, installation activation, connector lifecycle events) and cannot be\ncreated directly via the API.\n\nExactly one of `team`, `user`, `agent`, or `org` must identify the owner of the new\nsource. Omit `org` when an individual owner (`team`, `user`, or `agent`) is supplied;\ninclude `org` alone for org-level system-owned sources.\n", + "operationId": "post_api_v1_knowledge_sources", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "metadata": { + "key": "value" + }, + "org": "string", + "parent_source": "string", + "payload": {}, + "state": "string", + "team": "string", + "thread": "string", + "type": "string", + "user": "string" + }, + "properties": { + "agent": { + "description": "Agent ID (`agt_...`) that owns this source. Mutually exclusive with `team` and `user`.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata to attach to the source. Returned as-is on reads.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "Organization ID (`org_...`). Required for system-owned sources that have no individual owner (`team`, `user`, or `agent`).", + "example": "string", + "type": "string" + }, + "parent_source": { + "description": "Parent knowledge source ID (`ksrc_...`). Use to create a child source.", + "example": "string", + "type": "string" + }, + "payload": { + "description": "Type-specific configuration for the source. Shape depends on `type`.", + "example": {}, + "type": "object" + }, + "state": { + "description": "Initial state of the source. One of `\"active\"` (default) or `\"paused\"`. Paused sources do not trigger ingestion automatically.", + "example": "string", + "type": "string" + }, + "team": { + "description": "Team ID (`team_...`) that owns this source. Mutually exclusive with `user` and `agent`.", + "example": "string", + "type": "string" + }, + "thread": { + "description": "Thread ID (`thr_...`) to associate this source with, if applicable.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Knowledge source type. Must be one of the values returned by `GET /api/v1/knowledge_sources/kinds`.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) that owns this source. Mutually exclusive with `team` and `agent`.", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KnowledgeSource" + } + } + }, + "description": "The newly created knowledge source." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "422": { + "description": "Invalid parameters; Validation failed" + } + }, + "summary": "Create a knowledge source", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/knowledge_sources/kinds": { + "get": { + "description": "Returns the fixed set of knowledge source types that can be created directly via\n`POST /api/v1/knowledge_sources`. Use this endpoint to discover valid values for the\n`type` param before calling the create endpoint.\n\nSource kinds populated by server-driven flows — such as `webhook/inbound`,\n`connectors/*/emails`, and `thread/messages` — are intentionally excluded from this\nlist, as they cannot be created through the API.\n", + "operationId": "get_api_v1_knowledge_sources_kinds", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KnowledgeSourceKindListResponse" + } + } + }, + "description": "List of knowledge source kinds available for creation via the API." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + } + }, + "summary": "List creatable knowledge source kinds", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/knowledge_sources/{source}": { + "delete": { + "description": "Permanently deletes the knowledge source identified by `source`. This action is\nirreversible — all documents, embeddings, and ingestion history associated with the\nsource are removed.\n\nThe authenticated caller must own the source or have sufficient permissions within its\nparent organization. Returns `204 No Content` on success.\n", + "operationId": "delete_api_v1_knowledge_sources__source", + "parameters": [ + { + "description": "Knowledge source ID (`ksrc_...`) to delete.", + "example": "string", + "in": "path", + "name": "source", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response. The source has been permanently deleted." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Knowledge source not found" + } + }, + "summary": "Delete a knowledge source", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the knowledge source identified by `source`. The authenticated caller must have\naccess to the source's parent organization or be the individual owner of the source.\n\nUse the list endpoint to retrieve many sources at once or to discover sources by type\nor owner.\n", + "operationId": "get_api_v1_knowledge_sources__source", + "parameters": [ + { + "description": "Knowledge source ID (`ksrc_...`) to retrieve.", + "example": "string", + "in": "path", + "name": "source", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KnowledgeSource" + } + } + }, + "description": "The requested knowledge source." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Knowledge source not found" + } + }, + "summary": "Retrieve a knowledge source", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "patch": { + "description": "Updates the mutable fields of an existing knowledge source and returns the updated\nobject. Only fields provided in the request body are changed; omitted fields retain\ntheir current values.\n\nYou can update the type-specific `payload`, the `metadata` map, and the `state`. To\npause a source and prevent automatic ingestion, set `state` to `\"paused\"`. To resume,\nset it back to `\"active\"`.\n", + "operationId": "patch_api_v1_knowledge_sources__source", + "parameters": [ + { + "description": "Knowledge source ID (`ksrc_...`) to update.", + "example": "string", + "in": "path", + "name": "source", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "metadata": { + "key": "value" + }, + "payload": {}, + "state": "string" + }, + "properties": { + "metadata": { + "description": "Arbitrary key-value metadata to attach to the source. Replaces the entire existing `metadata` map when provided.", + "example": { + "key": "value" + }, + "type": "object" + }, + "payload": { + "description": "Type-specific configuration to replace on the source. Shape depends on the source `type`. Replaces the entire existing `payload` when provided.", + "example": {}, + "type": "object" + }, + "state": { + "description": "Desired state of the source. One of `\"active\"` or `\"paused\"`. Paused sources do not trigger ingestion automatically.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KnowledgeSource" + } + } + }, + "description": "The updated knowledge source." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Knowledge source not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Update a knowledge source", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/knowledge_sources/{source}/ingest": { + "post": { + "description": "Starts an ingestion run on the specified knowledge source and returns the ingestion\nobject. Exactly one of two modes must be chosen per request:\n\n**Push mode** (`file` or `content`) — available for `knowledge/documents` sources only.\nSupply the document bytes either as a reference to an already-uploaded file (`file`) or\nas an inline blob (`content`). The runner stores the bytes and indexes the resulting\ndocument. `title` and `metadata` are persisted on the document in push mode.\n\n**Pull mode** (`pull: true`) — re-triggers ingestion using the source's own configured\ndata. Use this to re-scrape a `scrape/site`, re-fetch a `web/link`, or re-process a\n`file/document`. Not valid for `knowledge/documents` (which has no upstream — push new\nbytes instead) or for source kinds populated by server-driven flows. `title` and\n`metadata` are ignored in pull mode.\n\nIf an ingestion is already active for the source, the existing ingestion is returned\nrather than creating a duplicate.\n", + "operationId": "post_api_v1_knowledge_sources__source_ingest", + "parameters": [ + { + "description": "Knowledge source ID (`ksrc_...`) to ingest.", + "example": "string", + "in": "path", + "name": "source", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "content": { + "content_type": "application/json", + "data": "string", + "data_encoding": "string", + "filename": "string" + }, + "dedupe": true, + "file": "string", + "metadata": { + "key": "value" + }, + "pull": true, + "title": "Example Title" + }, + "properties": { + "content": { + "description": "Inline document bytes to push to the source. Mutually exclusive with `file` and `pull`.", + "example": { + "content_type": "application/json", + "data": "string", + "data_encoding": "string", + "filename": "string" + }, + "properties": { + "content_type": { + "description": "MIME type of the content, e.g. `\"application/pdf\"` or `\"text/plain\"`.", + "example": "application/json", + "type": "string" + }, + "data": { + "description": "The raw document bytes. When `data_encoding` is `\"base64\"`, provide the base64-encoded representation of the binary content.", + "example": "string", + "type": "string" + }, + "data_encoding": { + "description": "Encoding format of `data`. One of `\"raw\"` (default, plain text) or `\"base64\"` (binary content such as images or PDFs, decoded server-side before storage).", + "example": "string", + "type": "string" + }, + "filename": { + "description": "Original filename for the document, e.g. `\"report.pdf\"`.", + "example": "string", + "type": "string" + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "dedupe": { + "description": "When `true`, reuse the source's existing document if the pushed content is byte-identical to it, instead of creating a duplicate. The reused document keeps its chunks and embeddings, and `title`/`metadata` from this request are still applied to it. Content that differs in any way always creates a new document. Defaults to `false`, which creates a new document on every push. Push mode only — not valid with `pull: true`. Check `metadata.document_reused` on the returned ingestion to see whether a document was actually reused.", + "example": true, + "type": "boolean" + }, + "file": { + "description": "ID of an already-uploaded file (`fil_...`). The runner reads filename and content type from the stored file. Upload the file via `POST /v1/files` first. Mutually exclusive with `content` and `pull`.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata to attach to the ingested document. Applied in push mode only; ignored when `pull: true`.", + "example": { + "key": "value" + }, + "type": "object" + }, + "pull": { + "description": "When `true`, re-triggers ingestion using the source's own configured data. Re-scrapes a `scrape/site`, re-fetches a `web/link`, or re-processes a `file/document`. Mutually exclusive with `file` and `content`. Not valid for `knowledge/documents` sources.", + "example": true, + "type": "boolean" + }, + "title": { + "description": "Display title for the ingested document. Applied in push mode only; ignored when `pull: true`.", + "example": "Example Title", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContextIngestion" + } + } + }, + "description": "The created ingestion, or an existing active ingestion if one is already running." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Knowledge source not found" + }, + "422": { + "description": "Invalid parameters" + }, + "429": { + "description": "Too many requests" + } + }, + "summary": "Trigger ingestion on a knowledge source", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/kv": { + "get": { + "description": "Returns key-value storage entries in one of two modes depending on the caller's\nauth scope.\n\n**User-JWT callers** receive a flat list of all their own entries with no\npagination fields. The `page`, `page_size`, `user`, `user_search`, and `key`\nparams are ignored.\n\n**Developer and server-to-server callers** receive a page-based paginated\nresponse across all users within the caller's app. Use `user` to scope results\nto a single user, `user_search` to do a substring match on email or full name,\nand `key` to filter entries whose key starts with the given prefix. Results are\nordered by creation time descending.\n", + "operationId": "get_api_v1_kv", + "parameters": [ + { + "description": "Page number to retrieve. Applies to developer and server-to-server callers only. Defaults to 1.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of entries per page. Applies to developer and server-to-server callers only. Defaults to 25; maximum is 100.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Filter results to entries belonging to this user ID. Applies to developer and server-to-server callers only.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Substring match against user email address and full name. Applies to developer and server-to-server callers only.", + "example": "string", + "in": "query", + "name": "user_search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Prefix filter on the storage key. Returns only entries whose key starts with this string. Applies to developer and server-to-server callers only.", + "example": "string", + "in": "query", + "name": "key", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyValueStorageEntryPage" + } + } + }, + "description": "Key-value storage entries for the current page, with pagination metadata for developer and server-to-server callers." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + } + }, + "summary": "List key-value storage entries", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new key-value storage entry for the target user under the given key.\nThe key must not already exist for this user; use the upsert endpoint to create\nor overwrite in a single call.\n\nEnd-user (user-JWT) callers always write to their own storage. Developer and\nserver-to-server callers must supply a `user` param identifying the target user\nwithin their app's scope. Attempting to write for a user in a different app\nreturns 404.\n", + "operationId": "post_api_v1_kv", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "key": "string", + "user": "string", + "value": "string" + }, + "properties": { + "key": { + "description": "Storage key for the entry. Must be a non-empty string unique to this user.", + "example": "string", + "type": "string" + }, + "user": { + "description": "Target user ID. Required when calling as a developer or with a server-to-server key; ignored for end-user callers.", + "example": "string", + "type": "string" + }, + "value": { + "description": "Value to store under `key`. Must be a non-empty string.", + "example": "string", + "type": "string" + } + }, + "required": [ + "key", + "value" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyValueStorageEntry" + } + } + }, + "description": "The newly created key-value storage entry." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden; App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "User not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Create a key-value storage entry", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/kv/{key}": { + "delete": { + "description": "Permanently deletes the key-value storage entry identified by `key` for the\ntarget user. Returns 204 No Content on success and 404 if the entry does not\nexist.\n\nEnd-user (user-JWT) callers can only delete entries they own. Developer and\nserver-to-server callers must supply a `user` param identifying the target user\nwithin their app's scope.\n", + "operationId": "delete_api_v1_kv__key", + "parameters": [ + { + "description": "Storage key of the entry to delete. Must be a non-empty string.", + "example": "string", + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response body. HTTP 204 No Content on success." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden; App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Entry not found; User not found" + } + }, + "summary": "Delete a key-value storage entry", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the key-value storage entry identified by `key` for the target user.\nReturns 404 if no entry exists for that key.\n\nEnd-user (user-JWT) callers retrieve entries from their own storage. Developer\nand server-to-server callers must supply a `user` param identifying the target\nuser within their app's scope.\n", + "operationId": "get_api_v1_kv__key", + "parameters": [ + { + "description": "Storage key of the entry to retrieve. Must be a non-empty string.", + "example": "string", + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Target user ID. Required when calling as a developer or with a server-to-server key; ignored for end-user callers.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyValueStorageEntry" + } + } + }, + "description": "The key-value storage entry for the given key." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden; App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Entry not found; User not found" + } + }, + "summary": "Retrieve a key-value storage entry", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "put": { + "description": "Creates a new key-value storage entry for the given `key`, or overwrites the\nvalue if an entry already exists. This is the idempotent alternative to the\ncreate endpoint: safe to call regardless of whether the key already exists.\n\nEnd-user (user-JWT) callers always write to their own storage. Developer and\nserver-to-server callers must supply a `user` param identifying the target user\nwithin their app's scope. Attempting to write for a user in a different app\nreturns 404.\n", + "operationId": "put_api_v1_kv__key", + "parameters": [ + { + "description": "Storage key to create or overwrite. Must be a non-empty string.", + "example": "string", + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "user": "string", + "value": "string" + }, + "properties": { + "user": { + "description": "Target user ID. Required when calling as a developer or with a server-to-server key; ignored for end-user callers.", + "example": "string", + "type": "string" + }, + "value": { + "description": "New value to store under `key`. Must be a non-empty string. Replaces any existing value.", + "example": "string", + "type": "string" + } + }, + "required": [ + "value" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyValueStorageEntry" + } + } + }, + "description": "The created or updated key-value storage entry." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden; App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "User not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Create or update a key-value storage entry", + "x-auth": [ + "publishable_key", + "bearer" + ], + "x-sdk-name": "upsert" + } + }, + "/api/v1/notification_preferences": { + "delete": { + "description": "Removes the authenticated user's explicit notification preference for a\ngiven `(type, channel)` combination, reverting that slot to the type's\ndefault channel set.\n\nThe `app_id` param scopes the deletion to a specific app's preference\nrow. Omit `app_id` to target the system-level (no-app) slot. Because\nthe two slots are stored independently, omitting `app_id` will not\nmatch a row that has one set, and vice versa.\n\nReturns `204 No Content` on success. Returns `404` if no preference\nexists for the given composite key.\n", + "operationId": "delete_api_v1_notification_preferences", + "parameters": [], + "responses": { + "204": { + "description": "Empty response body. A `204 No Content` status indicates the preference was deleted successfully." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Notification preference not found" + } + }, + "summary": "Delete a notification preference", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns all explicit notification preferences belonging to the authenticated\nuser. Preferences are returned for every `(type, channel)` combination the\nuser has explicitly configured; slots that have not been overridden are not\nincluded and fall back to the type's defaults.\n\nThe recipient is derived from the authenticated viewer. You cannot retrieve\npreferences for any other user through this endpoint. All configured\npreferences — system-level and app-scoped — are returned together in the\n`data` array.\n", + "operationId": "get_api_v1_notification_preferences", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationPreferenceList" + } + } + }, + "description": "An object with a `data` array containing all explicit notification preferences for the authenticated user." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + } + }, + "summary": "List notification preferences", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "put": { + "description": "Creates or replaces the authenticated user's notification preference for a\ngiven `(type, channel)` combination. This is an idempotent PUT: if no\npreference exists for the composite key, a new row is created; if one\nalready exists, its `enabled` flag is updated to the value you provide.\n\nThe recipient is derived from the authenticated viewer. You cannot set\npreferences for another user through this endpoint.\n\nPass `app_id` to scope the preference to a specific app's notifications —\nmost useful for the `app_*` notification type family. Omit `app_id` to\nconfigure the system-level (no-app) slot. System-level and app-scoped\npreferences are stored independently and do not overwrite each other.\n\nThe `in_app` channel is not configurable and will be rejected with a\nvalidation error if supplied.\n", + "operationId": "put_api_v1_notification_preferences", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "app_id": "string", + "channel": "string", + "enabled": true, + "type": "string" + }, + "properties": { + "app_id": { + "description": "App to scope this preference to. Omit to configure the system-level (no-app) slot. App-scoped and system-level preferences are stored separately and do not affect each other.", + "example": "string", + "type": "string" + }, + "channel": { + "description": "Delivery channel to configure (e.g., `\"email\"`, `\"sms\"`). The `in_app` channel is not configurable and will be rejected with a validation error.", + "example": "string", + "type": "string" + }, + "enabled": { + "description": "Whether the specified channel should be enabled for this notification type and scope. Set to `false` to suppress delivery on this channel.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "Notification type to configure. Use a builtin name (e.g., `\"app_info\"`, `\"billing_alert\"`) or a `\"custom:\"` identifier matching a NotificationType config registered in your app's bundle. Unknown type identifiers are rejected with a validation error.", + "example": "string", + "type": "string" + } + }, + "required": [ + "type", + "channel", + "enabled" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationPreference" + } + } + }, + "description": "The created or updated notification preference reflecting the new `enabled` state." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Viewer has no recipient context (no associated user or developer account)." + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create or update a notification preference", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/notifications": { + "get": { + "description": "Returns a cursor-paginated list of inbox notifications for the authenticated\nuser, ordered by creation time descending (newest first). All status groups\nare included by default; pass `status` to narrow results to a specific group.\n\nEach notification's `rendered` field contains type-specific display data\nresolved at request time. Notifications whose type is no longer registered\nin the platform are rendered with `kind: \"unknown\"` rather than being omitted.\n\nPagination is forward-only: supply `after_cursor` from a previous response to\nfetch the next (older) page. The `before_cursor` field is always `null` for\nthis endpoint. Requires an app-scoped token.\n", + "operationId": "get_api_v1_notifications", + "parameters": [ + { + "description": "Filter by notification status. One of `\"all\"`, `\"active\"`, `\"unread\"`, `\"read\"`, or `\"archived\"`. Defaults to `\"all\"` when omitted.", + "example": "string", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of notifications to return per page. Defaults to 20; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque pagination cursor from a previous response's `after_cursor` field. Omit to fetch the most recent notifications.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Cursor-paginated list of notifications for the authenticated user.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "archived_at": "2024-01-01T00:00:00Z", + "created_at": "2024-01-01T00:00:00Z", + "id": "ntf_0aBcDeFgHiJkLmNoPqRsTu", + "read_at": "2024-01-01T00:00:00Z", + "rendered": {}, + "status": "unread", + "type": "app_info" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor to pass as `after_cursor` on the next request to fetch older notifications. `null` when this is the last page.", + "example": "string", + "type": "string" + }, + "before_cursor": { + "description": "Always `null` — inbox pagination is forward-only and does not support fetching newer pages via cursor.", + "example": "string", + "type": "string" + }, + "data": { + "description": "Array of notification objects for the current page, ordered newest first.", + "example": [ + { + "archived_at": "2024-01-01T00:00:00Z", + "created_at": "2024-01-01T00:00:00Z", + "id": "ntf_0aBcDeFgHiJkLmNoPqRsTu", + "read_at": "2024-01-01T00:00:00Z", + "rendered": {}, + "status": "unread", + "type": "app_info" + } + ], + "items": { + "description": "An inbox notification delivered to a recipient user. Includes type-specific render data resolved at request time.", + "example": { + "archived_at": "2024-01-01T00:00:00Z", + "created_at": "2024-01-01T00:00:00Z", + "id": "ntf_0aBcDeFgHiJkLmNoPqRsTu", + "read_at": "2024-01-01T00:00:00Z", + "rendered": {}, + "status": "unread", + "type": "app_info" + }, + "properties": { + "archived_at": { + "description": "When the recipient archived this notification. `null` if the notification has not been archived.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_at": { + "description": "When the notification was sent (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Notification ID (`ntf_...`).", + "example": "ntf_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "read_at": { + "description": "When the recipient marked this notification read. `null` if the notification has not been read.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "rendered": { + "description": "Type-specific render spec resolved at request time. All types include `title`, `kind`, and `actions`; custom types may add their own keys. Notifications whose type is no longer registered render with `kind: \"unknown\"`.", + "example": {}, + "type": "object" + }, + "status": { + "description": "Current read state of the notification. One of `\"unread\"`, `\"read\"`, or `\"archived\"`.", + "example": "unread", + "type": "string" + }, + "type": { + "description": "Notification type slug, e.g. `\"app_info\"` for a built-in type or `\"custom:deploy_complete\"` for a custom type.", + "example": "app_info", + "type": "string" + } + }, + "required": [ + "id", + "type", + "status", + "rendered", + "created_at" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "description": "`true` if additional (older) notifications exist beyond this page; `false` if this is the last page.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Bad request; Invalid cursor" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + } + }, + "summary": "List a user's notifications", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/notifications/read_all": { + "post": { + "description": "Marks every `\"unread\"` notification belonging to the authenticated user as\n`\"read\"` in a single operation. Notifications that are already `\"read\"` or\n`\"archived\"` are not affected.\n\nThis call is safe to retry — if there are no unread notifications, it\nsucceeds without error. Requires an app-scoped token. Returns 204 No Content\non success.\n", + "operationId": "post_api_v1_notifications_read_all", + "parameters": [], + "responses": { + "204": { + "description": "No content" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + } + }, + "summary": "Mark all notifications as read", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/notifications/send": { + "post": { + "description": "Delivers a custom-typed notification to one of the calling app's users.\nApps define notification types by declaring `NotificationType` config objects\nin their bundle (one per `lookup_key`). Supply the type as\n`\"custom:\"` and provide a `data` map that is merged with\nplatform-provided context to render the notification's display fields.\n\nOnly app-scoped tokens may call this endpoint — user tokens are rejected with\n403. The app scope is stamped onto the notification automatically; an app\ncannot target recipients outside its tenant. Built-in platform types such as\n`\"app_info\"` and `\"billing_alert\"` are not accepted here.\n\nPass `idempotency_key` to deduplicate sends. If you call this endpoint twice\nwith the same `idempotency_key` for the same recipient, the second call\nreturns the original notification without creating a duplicate. The key is\nscoped to the calling app, so the same raw key used by different apps cannot\ncollide.\n", + "operationId": "post_api_v1_notifications_send", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "data": {}, + "idempotency_key": "string", + "type": "string", + "user": "string" + }, + "properties": { + "data": { + "description": "Arbitrary key-value payload merged with platform-provided context (recipient, app, org, brand) when rendering the notification's display fields. Defaults to an empty object when omitted.", + "example": {}, + "type": "object" + }, + "idempotency_key": { + "description": "Optional deduplication key. A second call with the same `idempotency_key` for the same recipient returns the originally-created notification without inserting a new record. Scoped per calling app.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Custom notification type identifier in the form `\"custom:\"`, where `` matches a `NotificationType` config declared in the calling app's bundle.", + "example": "string", + "type": "string" + }, + "user": { + "description": "Recipient user ID (`usr_...`). Must be a member of the calling app's tenant.", + "example": "string", + "type": "string" + } + }, + "required": [ + "type", + "user" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Notification" + } + } + }, + "description": "The created notification, or the existing notification when deduplicated by `idempotency_key`." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "User not found" + }, + "422": { + "description": "Invalid parameters; No NotificationType config matched this `custom:` in the calling app's bundle." + } + }, + "summary": "Send a custom notification to a user", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/notifications/unread_count": { + "get": { + "description": "Returns the total number of `\"unread\"` notifications for the authenticated\nuser. Useful for displaying a badge or indicator in your UI without\nfetching the full notification list.\n\nNotifications with `\"read\"` or `\"archived\"` status are not included in the\ncount. Requires an app-scoped token.\n", + "operationId": "get_api_v1_notifications_unread_count", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Object containing the count of unread notifications for the authenticated user.", + "example": { + "count": 1 + }, + "properties": { + "count": { + "description": "Total number of notifications with `\"unread\"` status belonging to the authenticated user.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "count" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + } + }, + "summary": "Get the unread notification count", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/notifications/{notification}/archive": { + "post": { + "description": "Moves a notification to `\"archived\"` status regardless of whether it is\ncurrently `\"unread\"` or `\"read\"`. Archived notifications are excluded from\nthe default inbox view but remain retrievable by passing `status: \"archived\"`\nto the list endpoint.\n\nThe authenticated user must own the notification. Passing a notification ID\nthat belongs to a different user returns a 404. If the notification is\nalready archived this call succeeds without error (idempotent).\n\nRequires an app-scoped token. Returns 204 No Content on success.\n", + "operationId": "post_api_v1_notifications__notification_archive", + "parameters": [ + { + "description": "Notification ID (`ntf_...`) to archive. Must belong to the authenticated user.", + "example": "string", + "in": "path", + "name": "notification", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "No content" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Notification not found" + } + }, + "summary": "Archive a notification", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/notifications/{notification}/read": { + "post": { + "description": "Transitions a notification from `\"unread\"` to `\"read\"` status. If the\nnotification is already `\"read\"` or `\"archived\"`, the call succeeds without\nchanging its status (idempotent).\n\nThe authenticated user must own the notification. Passing a notification ID\nthat belongs to a different user returns a 404. Requires an app-scoped token.\nReturns 204 No Content on success.\n", + "operationId": "post_api_v1_notifications__notification_read", + "parameters": [ + { + "description": "Notification ID (`ntf_...`) to mark as read. Must belong to the authenticated user.", + "example": "string", + "in": "path", + "name": "notification", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "No content" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Notification not found" + } + }, + "summary": "Mark a notification as read", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/notifications/{notification}/unarchive": { + "post": { + "description": "Restores an `\"archived\"` notification to its previous active status:\n`\"read\"` if the notification had been read before archiving, or `\"unread\"`\notherwise. The notification will appear again in the default inbox view.\n\nThe authenticated user must own the notification. Passing a notification ID\nthat belongs to a different user returns a 404. If the notification is not\ncurrently archived this call succeeds without changing its status (idempotent).\nRequires an app-scoped token. Returns 204 No Content on success.\n", + "operationId": "post_api_v1_notifications__notification_unarchive", + "parameters": [ + { + "description": "Notification ID (`ntf_...`) to unarchive. Must belong to the authenticated user.", + "example": "string", + "in": "path", + "name": "notification", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "No content" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Notification not found" + } + }, + "summary": "Unarchive a notification", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/orgs": { + "get": { + "description": "Returns a paginated list of organizations within the authenticated app scope,\noptionally filtered by a free-text search term matched against name, slug, and\ndomain (case-insensitive). Results are ordered by relevance when a search term\nis provided, and by creation time descending otherwise.\n\nThe response includes only public-facing organization fields: ID, name, domain,\nand logo. Use the developer-scoped org endpoints to access full organization\nrecords.\n\nPagination is offset-based. Pass `page` and `page_size` to navigate through\nresults. The `has_next` and `has_prev` fields indicate whether adjacent pages\nexist.\n", + "operationId": "get_api_v1_orgs", + "parameters": [ + { + "description": "Free-text search term matched against organization name, slug, and domain (case-insensitive). Omit to return all organizations in the app.", + "example": "string", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Page number to retrieve, starting at `1`. Defaults to `1` when omitted.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of organizations to return per page. Defaults to `25`; maximum is `100`.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Paginated list of organizations matching the query.", + "example": { + "data": [ + { + "domain": "acme.com", + "id": "org_0aBcDeFgHiJkLmNoPqRsTu", + "name": "Example Name" + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 1, + "total_entries": 1, + "total_pages": 1 + }, + "properties": { + "data": { + "description": "Array of organization objects for the current page.", + "example": [ + { + "domain": "acme.com", + "id": "org_0aBcDeFgHiJkLmNoPqRsTu", + "name": "Example Name" + } + ], + "items": { + "description": "A minimal organization object returned on authenticated endpoints. Exposes only the fields safe for any authenticated user: identity, display name, primary domain, and logo.", + "example": { + "domain": "acme.com", + "id": "org_0aBcDeFgHiJkLmNoPqRsTu", + "name": "Example Name" + }, + "properties": { + "domain": { + "description": "Primary domain associated with the organization, e.g. `\"acme.com\"`.", + "example": "acme.com", + "type": "string" + }, + "id": { + "description": "Organization ID (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "name": { + "description": "Display name of the organization.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id", + "name", + "domain" + ], + "type": "object" + }, + "type": "array" + }, + "has_next": { + "description": "`true` when a subsequent page exists; `false` on the last page.", + "example": true, + "type": "boolean" + }, + "has_prev": { + "description": "`true` when a previous page exists; `false` on the first page.", + "example": true, + "type": "boolean" + }, + "page": { + "description": "The current page number returned.", + "example": 1, + "type": "integer" + }, + "page_size": { + "description": "The number of results per page used for this response.", + "example": 1, + "type": "integer" + }, + "total_entries": { + "description": "Total number of organizations matching the query across all pages.", + "example": 1, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages for the current query and page size.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + } + }, + "summary": "Search organizations", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/private_service_definitions/{app_id}/{private_service_id}": { + "get": { + "description": "Returns the canonical callable definition authorized by an enrollment token.", + "operationId": "get_api_v1_private_service_definitions__app_id__private_service_id", + "parameters": [ + { + "example": "string", + "in": "path", + "name": "app_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "example": "string", + "in": "path", + "name": "private_service_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "format": "binary", + "type": "string" + } + } + }, + "description": "Raw content" + }, + "401": { + "description": "Invalid enrollment token" + }, + "404": { + "description": "Not found" + }, + "503": { + "description": "Private service control is unavailable" + } + }, + "summary": "Download an enrolled private service definition" + } + }, + "/api/v1/private_service_enrollments": { + "get": { + "operationId": "get_api_v1_private_service_enrollments", + "parameters": [ + { + "description": "Organization ID or slug. Required for developer and server callers.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Page number. Defaults to 1.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Results per page. Defaults to 25; maximum is 100.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrivateServiceEnrollmentPage" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Bad request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "503": { + "description": "Private service control is unavailable" + } + }, + "summary": "List private service enrollments", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates or safely replaces an unreserved one-time connector enrollment token.", + "operationId": "post_api_v1_private_service_enrollments", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "org": "string", + "private_service": "string" + }, + "properties": { + "org": { + "description": "Organization ID or slug. Required for developer and server callers.", + "example": "string", + "type": "string" + }, + "private_service": { + "description": "Private service ID (`pvs_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "private_service" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatedPrivateServiceEnrollment" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Bad request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Conflict" + }, + "503": { + "description": "Private service control is unavailable" + } + }, + "summary": "Create a private service enrollment", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/private_service_enrollments/{private_service_enrollment_id}": { + "get": { + "operationId": "get_api_v1_private_service_enrollments__private_service_enrollment_id", + "parameters": [ + { + "description": "Organization ID or slug. Required for developer and server callers.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Canonical certificate-bound service identity.", + "example": "string", + "in": "path", + "name": "private_service_enrollment_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrivateServiceEnrollment" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Bad request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "503": { + "description": "Private service control is unavailable" + } + }, + "summary": "Retrieve a private service enrollment", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/private_services": { + "get": { + "operationId": "get_api_v1_private_services", + "parameters": [ + { + "description": "Organization ID or slug. Required for developer and server callers.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Page number. Defaults to 1.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Results per page. Defaults to 25; maximum is 100.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrivateServicePage" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Bad request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "503": { + "description": "Private service control is unavailable" + } + }, + "summary": "List private services", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates one immutable private service in the selected organization.", + "operationId": "post_api_v1_private_services", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "functions": [ + { + "description": "An example description.", + "input_schema": {}, + "name": "Example Name", + "output_schema": {} + } + ], + "org": "string" + }, + "properties": { + "functions": { + "description": "Complete callable contracts. Input schemas are required; output schemas are optional.", + "example": [ + { + "description": "An example description.", + "input_schema": {}, + "name": "Example Name", + "output_schema": {} + } + ], + "items": { + "description": "A documented callable operation exposed by a private service.", + "example": { + "description": "An example description.", + "input_schema": {}, + "name": "Example Name", + "output_schema": {} + }, + "properties": { + "description": { + "description": "Human-readable guidance describing when and why to call the operation.", + "example": "An example description.", + "type": "string" + }, + "input_schema": { + "description": "JSON Schema Draft 7 object describing the operation's argument object.", + "example": {}, + "type": "object" + }, + "name": { + "description": "Stable operation name used when invoking the private service.", + "example": "Example Name", + "type": "string" + }, + "output_schema": { + "description": "Optional JSON Schema Draft 7 object describing the successful result.", + "example": {}, + "type": "object" + } + }, + "required": [ + "name", + "description", + "input_schema" + ], + "type": "object" + }, + "type": "array" + }, + "org": { + "description": "Organization ID or slug. Required for developer and server callers.", + "example": "string", + "type": "string" + } + }, + "required": [ + "functions" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrivateService" + } + } + }, + "description": "The newly created private service." + }, + "400": { + "description": "Bad request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Conflict" + }, + "503": { + "description": "Private service control is unavailable" + } + }, + "summary": "Create a private service", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/private_services/{private_service_id}": { + "get": { + "operationId": "get_api_v1_private_services__private_service_id", + "parameters": [ + { + "description": "Organization ID or slug. Required for developer and server callers.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "example": "string", + "in": "path", + "name": "private_service_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrivateService" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Bad request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "503": { + "description": "Private service control is unavailable" + } + }, + "summary": "Retrieve a private service", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/sandboxes": { + "post": { + "description": "Creates a new sandbox for the caller's app. A sandbox is an isolated environment\nthat can hold its own set of API keys, allowing you to test integrations without\naffecting production data.\n\nThe caller must authenticate with app-scoped credentials. Org-scoped viewers\nmay create sandboxes for their organization; developers and all-powerful\ncallers may create app-level or org-scoped sandboxes. If `org` is supplied the\nsandbox is scoped to that organization; otherwise it defaults to the\nauthenticated viewer's organization.\n\nRemote-eval sandboxes may set `purpose: \"eval\"` with `expires_at` at creation;\nTTL is the sole cleanup mechanism for those sandboxes. Returns the new sandbox\nwith the auto-issued publishable key — use the create key endpoint to issue\nsecret keys.\n", + "operationId": "post_api_v1_sandboxes", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "name": "Example Name", + "org": "string", + "purpose": "string", + "slug": "example-slug" + }, + "properties": { + "expires_at": { + "description": "Optional eval sandbox expiry in ISO 8601 format. Must be paired with `purpose: \"eval\"`.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "name": { + "description": "Human-readable display name for the sandbox.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) to scope the sandbox to. Defaults to the authenticated viewer's organization when omitted.", + "example": "string", + "type": "string" + }, + "purpose": { + "description": "Optional sandbox purpose marker. Only `\"eval\"` is accepted, and it must be paired with `expires_at`.", + "example": "string", + "type": "string" + }, + "slug": { + "description": "URL-safe identifier for the sandbox. Must be unique within the app.", + "example": "example-slug", + "type": "string" + } + }, + "required": [ + "name", + "slug" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Sandbox" + } + } + }, + "description": "The newly created sandbox." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create a sandbox", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/sandboxes/{sandbox}": { + "delete": { + "description": "Soft-deletes the specified sandbox. The sandbox is marked deleted and\nimmediately hidden from list/get queries; all of its active keys are revoked.\nHard deletion (child data cascade) is scheduled immediately via the background\nsandbox deletion worker — the same path used for developer-app soft-delete.\n\nThe caller must authenticate with app-scoped credentials and be allowed to\nmodify the sandbox. Returns 204 on success. If the sandbox is missing or\nalready deleted, a 404 is returned.\n", + "operationId": "delete_api_v1_sandboxes__sandbox", + "parameters": [ + { + "description": "Sandbox ID (`dsb_...`) of the sandbox to delete.", + "example": "string", + "in": "path", + "name": "sandbox", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response with HTTP 204 status on successful deletion." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Sandbox not found" + } + }, + "summary": "Delete a sandbox", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the sandbox identified by `sandbox` that belongs to the caller's app.\nThe response includes the sandbox's associated keys (without full secret key\nvalues — full keys are only available at creation time).\n\nThe caller must authenticate with app-scoped credentials. Org members may view\ntheir org's sandboxes; developers and all-powerful callers may view app-level\nand org-scoped sandboxes in their app. Returns 404 if the sandbox does not\nexist or is not visible to the caller.\n", + "operationId": "get_api_v1_sandboxes__sandbox", + "parameters": [ + { + "description": "Sandbox ID (`dsb_...`) to retrieve.", + "example": "string", + "in": "path", + "name": "sandbox", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Sandbox" + } + } + }, + "description": "The requested sandbox." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Sandbox not found" + } + }, + "summary": "Retrieve a sandbox", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/sandboxes/{sandbox}/keys": { + "post": { + "description": "Issues a new API key for the specified sandbox. Keys can be either\n`\"publishable\"` (safe to embed in client-side code) or `\"secret\"` (server-side\nonly). The full key value is returned once in the `full_key` field of this\nresponse and is never retrievable again — store it securely immediately.\n\nThe caller must authenticate with app-scoped credentials and be able to\nmodify the sandbox (org members for org sandboxes; developers / all-powerful\nfor app-level). If the sandbox does not belong to the caller's app or is not\nvisible, a 404 is returned. Multiple active keys per sandbox are supported;\nrevoke individual keys with the revoke key endpoint.\n", + "operationId": "post_api_v1_sandboxes__sandbox_keys", + "parameters": [ + { + "description": "Sandbox ID (`dsb_...`). The key is created for this sandbox.", + "example": "string", + "in": "path", + "name": "sandbox", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "type": "string" + }, + "properties": { + "type": { + "description": "Key type. One of `\"publishable\"` or `\"secret\"`. Defaults to `\"publishable\"`.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxKey" + } + } + }, + "description": "The newly created sandbox key, including the one-time `full_key` value." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Sandbox not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create a sandbox key", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/slack_channel_bindings": { + "get": { + "description": "Returns a page of Slack channel bindings visible to the authenticated user.\nResults can be filtered by integration, team, agent, or organization. Omit all\nfilter params to retrieve every binding the caller can see.\n\nPagination is page-based. Pass `page` and `per_page` to navigate large result\nsets. `page` must be a positive integer; `per_page` must be between 1 and 100.\nInvalid values return 400.\n", + "operationId": "get_api_v1_slack_channel_bindings", + "parameters": [ + { + "description": "Return only bindings whose Slack integration matches one of these integration IDs. Omit to return bindings across all integrations.", + "example": [ + "string" + ], + "in": "query", + "name": "integration", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Return only bindings bound to one of these team IDs. Omit to return bindings for all teams.", + "example": [ + "string" + ], + "in": "query", + "name": "team", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Return only bindings that have at least one of these agent user IDs attached. Omit to return bindings regardless of agent attachment.", + "example": [ + "string" + ], + "in": "query", + "name": "agent", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Return only bindings that belong to one of these organization IDs. Omit to return bindings across all organizations visible to the caller.", + "example": [ + "string" + ], + "in": "query", + "name": "org", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Page number to retrieve, 1-indexed. Defaults to 1. Must be a positive integer.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of bindings to return per page. Defaults to 25; maximum is 100.", + "example": 1, + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SlackChannelBindingListResponse" + } + } + }, + "description": "Paginated list of Slack channel bindings visible to the caller." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "summary": "List Slack channel bindings", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new binding between a Slack channel and a team, or updates the\nexisting binding if one already exists for the given channel. The caller also\nsupplies a list of agents to attach to the binding and enroll as members of the\ndestination team.\n\nThe caller must have team-manage rights on the destination team (and on the\ncurrently bound team if the channel is being re-pointed). Returns 403 if\npermission is insufficient. All write steps are idempotent, so retrying after\na partial failure is safe.\n\nOn success the REST endpoint returns 201 Created. The script binding\n(`slack.channel_bindings.upsert`) returns the full binding object including the\nattached agents.\n", + "operationId": "post_api_v1_slack_channel_bindings", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent_user_ids": [ + "string" + ], + "allow_bot_conversations": true, + "channel_id": "string", + "customer_label": "string", + "is_ext_shared_cached": true, + "is_private_cached": true, + "slack_team_id": "string", + "team_id": "string" + }, + "properties": { + "agent_user_ids": { + "description": "List of agent user IDs to attach to the binding and enroll as members of the destination team. Pass an empty array to bind the channel without attaching any agents.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "allow_bot_conversations": { + "description": "Opt this channel into sustained bot-to-bot conversation: the reply loop brake is disabled for its mirror thread. Set when the counterparty is a known bot the agent should keep answering. Omitting the parameter leaves the stored value unchanged.", + "example": true, + "type": "boolean" + }, + "channel_id": { + "description": "Slack channel ID to bind (e.g. `C01234ABCDE`). Acts as the natural key of the binding within the workspace.", + "example": "string", + "type": "string" + }, + "customer_label": { + "description": "Human-readable label for the customer associated with this channel. Stored in the binding's config. `null` if omitted.", + "example": "string", + "type": "string" + }, + "is_ext_shared_cached": { + "description": "Cached value of Slack's `is_ext_shared` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. `null` if omitted.", + "example": true, + "type": "boolean" + }, + "is_private_cached": { + "description": "Cached value of Slack's `is_private` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. Private channels are member-managed. `null` if omitted.", + "example": true, + "type": "boolean" + }, + "slack_team_id": { + "description": "Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use.", + "example": "string", + "type": "string" + }, + "team_id": { + "description": "ID of the team to bind the Slack channel to. The caller must have team-manage rights on this team.", + "example": "string", + "type": "string" + } + }, + "required": [ + "slack_team_id", + "channel_id", + "team_id", + "agent_user_ids" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SlackChannelBinding" + } + } + }, + "description": "The created or updated Slack channel binding, including the full list of currently attached agents." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden; The Slack integration referenced by this binding is not visible to the caller" + }, + "404": { + "description": "Agent not found; Team not found" + }, + "409": { + "description": "Channel already has a resident agent" + }, + "422": { + "description": "Invalid parameters; Binding org_id does not match the integration's org_id" + } + }, + "summary": "Create or update a Slack channel binding", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/slack_channel_bindings/provision": { + "post": { + "description": "Opens a Slack Connect channel with a new customer — creating one and sending\nthe invite, or adopting a shared channel you already have — and records who is\nadding whom so the addition can finish once the customer accepts.\n\nThe returned binding is **pending**: nothing mirrors, and no per-customer Team,\nagent, or solution instance exists yet. Acceptance is asynchronous and may\nnever come. When it does, the addition completes in the background under the\nidentity of the admin who called this endpoint, re-checked live at that moment.\nA caller who has since lost their admin role does not get a substitute — the\naddition is refused and a human re-adds the customer.\n\nThe caller must be an admin of the Slack integration's own organization. This\nis the same authority the completion demands, checked here so a customer is\nnever invited into a channel whose addition can never finish.\n\nDeliberately not exposed as a script binding: this sends mail to a person\noutside the org, so it stays a vendor-admin HTTP surface.\n", + "operationId": "post_api_v1_slack_channel_bindings_provision", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "channel_name": "Example Name", + "customer_email": "user@example.com", + "customer_key": "string", + "customer_label": "string", + "existing_channel_id": "string", + "inputs": {}, + "slack_team_id": "string", + "template_config_id": "string" + }, + "properties": { + "channel_name": { + "description": "Name for a Slack channel to create for this customer. Required unless `existing_channel_id` is given. The channel is created private.", + "example": "Example Name", + "type": "string" + }, + "customer_email": { + "description": "Address the Slack Connect invite is sent to. Required when creating a channel; optional when adopting one the customer is already in. Whoever accepts becomes the verified counterparty.", + "example": "user@example.com", + "type": "string" + }, + "customer_key": { + "description": "The vendor's own primary key for this customer (`customer_id` / `account_id` / `tenant_id`). The per-customer agent's data access is locked to it. Immutable once the customer is added: re-targeting means offboarding and re-provisioning.", + "example": "string", + "type": "string" + }, + "customer_label": { + "description": "Human-readable name for the customer (e.g. `Acme, Inc.`). Used for the vendor's own dashboards and as the per-customer Team's name. Not an identity or an access control input.", + "example": "string", + "type": "string" + }, + "existing_channel_id": { + "description": "Adopt this already-shared Slack Connect channel (e.g. `C01234ABCDE`) instead of creating one. Mutually exclusive with `channel_name`.", + "example": "string", + "type": "string" + }, + "inputs": { + "description": "String-keyed values the per-customer solution instance is stamped with. Defaults to an empty map.", + "example": {}, + "type": "object" + }, + "slack_team_id": { + "description": "Slack workspace team ID of the vendor's own Slack installation (e.g. `T01234ABCDE`). The customer's workspace is not known yet — it resolves from whoever accepts.", + "example": "string", + "type": "string" + }, + "template_config_id": { + "description": "Config ID (`cfg_…`) of the org-installed Solution the per-customer instance is stamped from. Must be the organization's own installed copy, not the catalog original — instances stamped from a different config do not appear in the vendor's customer fleet.", + "example": "string", + "type": "string" + } + }, + "required": [ + "slack_team_id", + "customer_label", + "customer_key", + "template_config_id" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SlackChannelBinding" + } + } + }, + "description": "The pending binding for the customer's channel. `disclosure_state` is `pending` until the customer accepts, and `scope_key` is null until the addition finishes." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "402": { + "description": "Payment required" + }, + "403": { + "description": "Forbidden; Admin role required for this operation; The Slack integration referenced by this binding is not visible to the caller" + }, + "409": { + "description": "Conflict" + }, + "422": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + }, + "502": { + "description": "Provider returned an error; Service unavailable" + } + }, + "summary": "Start adding a customer over Slack Connect", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/slack_channel_bindings/{channel}": { + "delete": { + "description": "Removes the binding between a Slack channel and its associated team. The\nchannel is identified by its Slack channel ID together with the `slack_team_id`\nthat scopes it to a specific Slack workspace. Removing the binding does not\ndelete the bound team or any conversation threads scoped to it; decommission\nthose resources separately if required.\n\nThe caller must have team-manage rights on the team the channel is currently\nbound to. Returning 403 indicates insufficient permission; returning 404\nindicates the binding does not exist or is not visible to the caller.\n\nThe REST endpoint returns 204 No Content on success. The script binding\n(`slack.channel_bindings.delete`) returns a confirmation object so script\ncallers can verify success without an additional fetch. Both paths are\nidempotent — retrying after a partial failure is safe.\n", + "operationId": "delete_api_v1_slack_channel_bindings__channel", + "parameters": [ + { + "description": "Slack channel ID of the binding to delete (e.g. `C01234ABCDE`).", + "example": "string", + "in": "path", + "name": "channel", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Deletion confirmation returned by the script binding. The REST endpoint returns 204 No Content with no body.", + "example": { + "channel": "string", + "deleted": true + }, + "properties": { + "channel": { + "description": "Slack channel ID of the binding that was deleted.", + "example": "string", + "type": "string" + }, + "deleted": { + "description": "Always `true` when the binding was successfully removed.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "deleted", + "channel" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden; The Slack integration referenced by this binding is not visible to the caller" + }, + "404": { + "description": "Slack channel binding not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Delete a Slack channel binding", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the Slack channel binding identified by a Slack channel ID and workspace\nteam ID pair. Use this endpoint to look up the team and agents currently bound\nto a specific Slack channel.\n\nThe `channel` path parameter is the Slack channel ID; `slack_team_id` identifies\nthe Slack workspace the channel belongs to, disambiguating channels with the same\nID across workspaces. Both parameters are required. Returns 404 if no binding\nexists for the given pair or the associated Slack integration is not visible to\nthe caller.\n", + "operationId": "get_api_v1_slack_channel_bindings__channel", + "parameters": [ + { + "description": "Slack channel ID of the binding to retrieve (e.g. `C01234ABCDE`).", + "example": "string", + "in": "path", + "name": "channel", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Used together with `channel` to uniquely identify the binding.", + "example": "string", + "in": "query", + "name": "slack_team_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SlackChannelBinding" + } + } + }, + "description": "The Slack channel binding for the given channel and workspace." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "The Slack integration referenced by this binding is not visible to the caller" + }, + "404": { + "description": "Slack channel binding not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Retrieve a Slack channel binding", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/slack_channel_bindings/{channel}/delivery_outcomes": { + "get": { + "description": "Returns what happened to each agent message this platform sent to a Slack\nchannel, newest attempt first.\n\nA message that never appears in a Slack channel has several possible causes\nthat look identical from the channel itself: a content guard withheld it, the\ncross-org judge refused it, Slack rejected the call, or nobody asked anything.\nThis endpoint tells them apart. Use it to confirm a reply was delivered, or to\nfind out why one never arrived, without reading the channel's mirrored\nconversation.\n\nOutcomes cover **outbound agent messages only**. They carry no message\ncontent, no author, and nothing about inbound messages. Access follows the\nchannel's binding — the organization and app the channel is bound to — and\nneeds no membership in the mirrored thread.\n\nPaginated with opaque cursors, newest first. When `has_more` is true, pass the\nresponse's `before_cursor` back as `before_cursor` to continue into older\nhistory. `since` and `outcome` narrow the result set; they are filters, not\npaging controls.\n", + "operationId": "get_api_v1_slack_channel_bindings__channel_delivery_outcomes", + "parameters": [ + { + "description": "Slack channel ID to read delivery outcomes for (e.g. `C01234ABCDE`).", + "example": "string", + "in": "path", + "name": "channel", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Only return attempts at or after this ISO 8601 timestamp (e.g. `2026-08-11T00:00:00Z`). Omit to return the most recent attempts regardless of age.", + "example": "string", + "in": "query", + "name": "since", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return only attempts with this outcome. Omit to return every outcome. Use `floored` and `judge_refused` to see only what was withheld.", + "example": "delivered", + "in": "query", + "name": "outcome", + "required": false, + "schema": { + "enum": [ + "delivered", + "floored", + "judge_refused", + "failed" + ], + "type": "string" + } + }, + { + "description": "Maximum number of outcomes to return. Defaults to 50; maximum is 200.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor from a previous response; returns outcomes older than it. Cursors are not parseable and are only valid against this endpoint.", + "example": "string", + "in": "query", + "name": "before_cursor", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Opaque cursor from a previous response; returns outcomes newer than it. Suited to a UI loading newer entries. To poll for everything recorded since a point in time, prefer `since` with a little overlap and de-duplicate on `id` — `after_cursor` can miss an attempt recorded in the same millisecond as the cursor's own row.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SlackDeliveryOutcomeListResponse" + } + } + }, + "description": "Delivery outcomes for the requested channel, newest first." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "List delivery outcomes for a Slack channel", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/slack_channel_bindings/{channel}/deposit_thread": { + "post": { + "description": "Sets the binding's deposit target — the internal staging thread the\ndeposit pipe copies this channel's mirror content into. Pass a `null`\n`thread_id` to turn the pipe off.\n\nThe target is validated server-side: it must exist, belong to the\nbinding's app and org, and never be a Slack mirror thread. Customer\nbindings (bound `team_id`) additionally require a team-owned private\nthread with no participant list, so the staging read ACL stays governed\nby the channel-membership projection. Re-pointing or clearing an\nexisting target purges the old thread's deposit entries.\n", + "operationId": "post_api_v1_slack_channel_bindings__channel_deposit_thread", + "parameters": [ + { + "description": "Slack channel ID whose binding is being configured (e.g. `C01234ABCDE`).", + "example": "string", + "in": "path", + "name": "channel", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "slack_team_id": "string", + "thread_id": "string" + }, + "properties": { + "slack_team_id": { + "description": "Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use.", + "example": "string", + "type": "string" + }, + "thread_id": { + "description": "Staging thread ID (primary key, `thr_…`) deposits should flow into. Pass `null` to turn the pipe off.", + "example": "string", + "type": "string" + } + }, + "required": [ + "slack_team_id" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SlackChannelBinding" + } + } + }, + "description": "The binding with the updated deposit config." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden; The Slack integration referenced by this binding is not visible to the caller" + }, + "404": { + "description": "Not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Point a Slack channel's deposit pipe at a staging thread, or turn it off", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/solution_categories": { + "get": { + "description": "Returns a paginated list of solution category definitions visible to the authenticated caller.\nUse filters to narrow results by key, parent key, lookup key, or virtual path prefix.\n\nResults are scoped to categories accessible under the caller's viewer context. Pass `app` to\nrestrict the listing to categories associated with a specific app scope. Omit `owners` to\nreturn categories from all ownership scopes (`\"system\"` and `\"org\"`) that the caller can see.\n\nPagination is page-based. Use `page` and `page_size` to navigate large result sets. The\nresponse includes `total_entries`, `total_pages`, `has_next`, and `has_prev` to support\npagination controls. `total_entries` reflects the count after key deduplication.\n", + "operationId": "get_api_v1_solution_categories", + "parameters": [ + { + "description": "Page number to retrieve, 1-indexed. Defaults to `1`.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of solution categories to return per page. Defaults to `25`.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Return only categories whose key exactly matches one of the provided values.", + "example": [ + "string" + ], + "in": "query", + "name": "keys", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Return only categories whose parent key matches one of the provided values. Pass an empty array to return root-level categories.", + "example": [ + "string" + ], + "in": "query", + "name": "parent_keys", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Return only the category whose `lookup_key` exactly matches this value.", + "example": "string", + "in": "query", + "name": "lookup_key", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return only categories whose `virtual_path` starts with this prefix.", + "example": "string", + "in": "query", + "name": "path_prefix", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Restrict results to categories owned by the specified scopes. Accepted values are `\"system\"` and `\"org\"`. Omit to include all ownership scopes visible to the caller.", + "example": [ + "string" + ], + "in": "query", + "name": "owners", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SolutionCategoryListResponse" + } + } + }, + "description": "Paginated list of solution category summaries matching the applied filters." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden — app scope required" + } + }, + "summary": "List solution categories", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/solution_instances": { + "get": { + "description": "Returns a forward cursor-paginated page of customer instances stamped from one\nsolution template. Results are restricted to the caller's organization; an\napp-wide viewer without an organization scope is forbidden.\n\nPass `after_cursor` from a response with `has_more: true` to retrieve the next\npage. Each row includes the materialized agent, pinned template version, and\nlocal-edit count computed by the solution-instance read path.\n", + "operationId": "get_api_v1_solution_instances", + "parameters": [ + { + "description": "ID of the installed solution template whose customer instances should be listed.", + "example": "string", + "in": "query", + "name": "solution_template_config_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of instances to return. Defaults to 50; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the preceding page. Omit to retrieve the first page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SolutionInstanceListResponse" + } + } + }, + "description": "Cursor-paginated customer solution instances visible to the caller." + }, + "400": { + "description": "Bad request; Invalid cursor" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + } + }, + "summary": "List customer solution instances", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/solution_tags": { + "get": { + "description": "Returns a paginated list of solution tag definitions visible to the authenticated\nuser, scoped to their app. Results include tags from both the system scope and the\ncaller's organization scope by default; use the `owners` parameter to restrict to\none or both.\n\nUse `keys` to fetch a specific set of tags by their stable key identifiers, or\n`lookup_key` to find a single tag by its lookup key. Use `path_prefix` to filter\ntags by virtual path hierarchy. Combine filters as needed; all supplied filters are\napplied together.\n\nPagination is page-based. Supply `page` and `page_size` to control which page is\nreturned. The response includes `total_entries`, `total_pages`, `has_next`, and\n`has_prev` fields for navigating the full result set.\n", + "operationId": "get_api_v1_solution_tags", + "parameters": [ + { + "description": "Page number to return. Defaults to 1.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of solution tags to return per page. Defaults to 25.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Return only solution tags whose `key` exactly matches one of the provided values.", + "example": [ + "string" + ], + "in": "query", + "name": "keys", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Return only the solution tag whose `lookup_key` exactly matches this value.", + "example": "string", + "in": "query", + "name": "lookup_key", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return only solution tags whose `virtual_path` starts with this prefix.", + "example": "string", + "in": "query", + "name": "path_prefix", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Restrict results to one or more owner scopes. Accepted values are `\"system\"` (app-level system tags) and `\"org\"` (tags belonging to the caller's organization). Omit to include all scopes visible to the caller.", + "example": [ + "string" + ], + "in": "query", + "name": "owners", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SolutionTagListResponse" + } + } + }, + "description": "Paginated list of solution tag definitions visible to the authenticated user." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden — app scope required" + } + }, + "summary": "List solution tags", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/solutions": { + "get": { + "description": "Returns a paginated list of Solutions visible to the caller, merging two\nscopes: app-level Solutions (system-owned rows with no org affiliation,\nvisible to everyone — including unauthenticated callers — so they can power\nthe public catalog) and org-level Solutions (system-owned rows stamped with\nthe viewer's org ID, included when an authenticated viewer carries an org\ncontext). Unauthenticated callers resolve to an app-scoped anonymous viewer\nand therefore only ever see the app-level scope.\n\nSolutions that appear under both scopes are deduplicated by their stable\n`solution_id` value. The merged entry's `owners` array lists every scope the\nSolution was found under (`\"system\"` and/or `\"org\"`). When the app-level copy\nhas a higher `solution_version` than the org-level copy, the response includes\n`upgrade_available: true` and `latest_version` so callers can prompt for an\nupgrade.\n", + "operationId": "get_api_v1_solutions", + "parameters": [ + { + "description": "Page number to return. Defaults to `1`.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of Solutions per page. Defaults to `25`.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Filter to the Solution whose `lookup_key` matches exactly.", + "example": "string", + "in": "query", + "name": "lookup_key", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to Solutions whose `virtual_path` starts with this prefix.", + "example": "string", + "in": "query", + "name": "path_prefix", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Restrict results to a subset of owner scopes. Accepted values: `\"system\"` (app-level Solutions) and `\"org\"` (viewer's org-level Solutions). Omit to include all scopes the viewer can see.", + "example": [ + "string" + ], + "in": "query", + "name": "owners", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SolutionListResponse" + } + } + }, + "description": "Paginated list of Solution summaries visible to the caller." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden — app scope required" + } + }, + "summary": "List Solutions", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Imports a Solution and its bundled configs (skills, scripts, templates, files)\ninto the library for the target scope. Two mutually exclusive import modes\nare supported: pass `solution` to re-import an existing system-owned catalog\nSolution by ID or `lookup_key`, or pass `solution_bundle` to supply a\nself-contained inline bundle. Exactly one must be present.\n\nThe operation upserts the bundle in a single transaction. When `dry_run` is\n`true` the same pipeline runs but the transaction is rolled back — no rows are\npersisted and the response reflects what would have been written. The\nresponse shape is the same in both cases: the Solution summary plus\n`installed_configs` listing each config the import created or would create.\n\nPairs with `POST /api/v1/solutions/:solution/install`: this endpoint puts the\nSolution into the library; install provisions a runtime resource (Agent,\nAgentRoutine, AgentTool, etc.) from an already-imported Solution.\n", + "operationId": "post_api_v1_solutions", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "dry_run": true, + "org": "string", + "solution": "string", + "solution_bundle": { + "configs": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "tools/my-tool.yaml" + } + ], + "lookup_key_prefix": "string", + "lookup_key_suffix": "string", + "setup_actions": [ + { + "depends_on": [ + "string" + ], + "description": "An example description.", + "kind": "env_var", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "title": "Example Title", + "verify_config": { + "key": "value" + } + } + ], + "skills": [ + { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "relative_path": "skills/my-skill/SKILL.md" + } + ], + "solution": { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "data_encoding": "raw", + "relative_path": "README.md" + } + ], + "lookup_key": "string" + }, + "template": { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + }, + "templates": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + } + ] + }, + "team": "string", + "user": "string", + "virtual_path_prefix": "string" + }, + "properties": { + "dry_run": { + "description": "When `true`, runs the full import pipeline but rolls back the transaction — no rows are persisted. The response reflects what would have been written. Defaults to `false`.", + "example": true, + "type": "boolean" + }, + "org": { + "description": "Organization ID (`org_...`) for the import destination scope.", + "example": "string", + "type": "string" + }, + "solution": { + "description": "Config ID (`cfg_...`) or `lookup_key` of an existing system-owned, org-less Solution to import into the target scope. Mutually exclusive with `solution_bundle`.", + "example": "string", + "type": "string" + }, + "solution_bundle": { + "description": "Self-contained inline bundle containing the Solution metadata plus all bundled configs (skills, templates, configs, files). Mutually exclusive with `solution`.", + "example": { + "configs": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "tools/my-tool.yaml" + } + ], + "lookup_key_prefix": "string", + "lookup_key_suffix": "string", + "setup_actions": [ + { + "depends_on": [ + "string" + ], + "description": "An example description.", + "kind": "env_var", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "title": "Example Title", + "verify_config": { + "key": "value" + } + } + ], + "skills": [ + { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "relative_path": "skills/my-skill/SKILL.md" + } + ], + "solution": { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "data_encoding": "raw", + "relative_path": "README.md" + } + ], + "lookup_key": "string" + }, + "template": { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + }, + "templates": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + } + ] + }, + "properties": { + "configs": { + "description": "Additional configs of any kind that the solution.yaml references and that should be upserted as part of this install.", + "example": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "tools/my-tool.yaml" + } + ], + "items": { + "description": "A supporting configuration resource included in a template bundle, such as a script, model config, or routine template referenced by the agent template.", + "example": { + "content": "string", + "content_type": "application/json", + "relative_path": "tools/my-tool.yaml" + }, + "properties": { + "content": { + "description": "Full text content of the configuration file.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the configuration content, e.g. `\"application/x-yaml\"` or `\"application/json\"`. `null` if not specified.", + "example": "application/json", + "type": "string" + }, + "relative_path": { + "description": "Bundle-relative path to this config file. The path determines the config kind and its storage identity within the installation.", + "example": "tools/my-tool.yaml", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "lookup_key_prefix": { + "description": "String prepended (with a `-` separator) to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Typical value is `solutions-`.", + "example": "string", + "type": "string" + }, + "lookup_key_suffix": { + "description": "String appended to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Should be stable for a given install and unique per attempt.", + "example": "string", + "type": "string" + }, + "setup_actions": { + "description": "Post-install setup checklist items for the wrapped template. Allowed only when the bundle contains a single template and that template's body does not already declare its own `setup_actions`. Omit when bundling multiple templates.", + "example": [ + { + "depends_on": [ + "string" + ], + "description": "An example description.", + "kind": "env_var", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "title": "Example Title", + "verify_config": { + "key": "value" + } + } + ], + "items": { + "description": "A post-install setup checklist item that the user must complete before the installed agent is fully operational.", + "example": { + "depends_on": [ + "string" + ], + "description": "An example description.", + "kind": "env_var", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "title": "Example Title", + "verify_config": { + "key": "value" + } + }, + "properties": { + "depends_on": { + "description": "List of other setup action identifiers that must be completed before this action becomes actionable.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "description": { + "description": "Markdown-formatted instructions or context shown beneath the checklist item. `null` if not provided.", + "example": "An example description.", + "type": "string" + }, + "kind": { + "description": "Category of setup step. One of `\"env_var\"` (configure an environment variable), `\"install\"` (complete an installation step), `\"custom\"` (a user-defined action), or `\"integration\"` (authorize an OAuth-backed MCP server integration).", + "example": "env_var", + "type": "string" + }, + "params": { + "description": "Kind-specific configuration for the action. For `\"env_var\"` steps this typically includes `key` and `scope`; for `\"install\"` steps it includes `installation_kind`; for `\"integration\"` steps it includes `mcp_server_ref`. Shape varies by `kind`.", + "example": { + "key": "value" + }, + "type": "object" + }, + "required": { + "description": "When `true`, this action must be completed before the checklist progress bar reaches 100%. Defaults to `true`.", + "example": true, + "type": "boolean" + }, + "sort_order": { + "description": "Numeric sort position controlling the display order of this action in the checklist. Defaults to `0` when not specified.", + "example": 1, + "type": "integer" + }, + "title": { + "description": "Short human-readable label displayed in the setup checklist.", + "example": "Example Title", + "type": "string" + }, + "verify_config": { + "description": "Configuration passed to the runtime verifier to determine whether the action has been completed, e.g. `{\"type\": \"secret_present\"}`. `null` if no automated verification is configured.", + "example": { + "key": "value" + }, + "type": "object" + } + }, + "required": [ + "kind", + "title" + ], + "type": "object" + }, + "type": "array" + }, + "skills": { + "description": "Skill bundles (root config plus supporting files) that this solution depends on.", + "example": [ + { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "relative_path": "skills/my-skill/SKILL.md" + } + ], + "items": { + "description": "A skill to install as part of a template bundle, consisting of a root `SKILL.md` definition and any accompanying support files.", + "example": { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "relative_path": "skills/my-skill/SKILL.md" + }, + "properties": { + "content": { + "description": "Full text content of the `SKILL.md` file.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the `SKILL.md` content. Defaults to `text/markdown` when omitted.", + "example": "application/json", + "type": "string" + }, + "files": { + "description": "Additional files nested inside the skill folder, each with its own path and content.", + "example": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "items": { + "description": "A single file nested inside a skill folder, included as part of an install bundle.", + "example": { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + }, + "properties": { + "content": { + "description": "Full text content of the file.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the file content. Defaults to a value inferred from the file extension when omitted.", + "example": "application/json", + "type": "string" + }, + "relative_path": { + "description": "Path of this file relative to the skill folder root, e.g. `\"skills/my-skill/helpers.md\"`.", + "example": "skills/my-skill/helpers.md", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "relative_path": { + "description": "Bundle-relative path to the skill root, which must end in `/SKILL.md` (e.g. `\"skills/my-skill/SKILL.md\"`).", + "example": "skills/my-skill/SKILL.md", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "solution": { + "description": "The solution config to install, including the solution.yaml body and any referenced component files.", + "example": { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "data_encoding": "raw", + "relative_path": "README.md" + } + ], + "lookup_key": "string" + }, + "properties": { + "content": { + "description": "Raw solution.yaml body (YAML or JSON). Describes the solution structure, template references, and asset declarations.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of `content`. Defaults to `application/x-yaml`; pass `application/json` when submitting JSON.", + "example": "application/json", + "type": "string" + }, + "files": { + "description": "Component files (READMEs, diagrams, fixtures) referenced by the solution.yaml via `path://` URIs. Each entry is persisted as a child file record.", + "example": [ + { + "content": "string", + "content_type": "application/json", + "data_encoding": "raw", + "relative_path": "README.md" + } + ], + "items": { + "description": "A component file included in a solution bundle, such as a README, diagram, or fixture referenced by the solution.yaml via a `path://` URI.", + "example": { + "content": "string", + "content_type": "application/json", + "data_encoding": "raw", + "relative_path": "README.md" + }, + "properties": { + "content": { + "description": "Raw content of the file. When `data_encoding` is `\"base64\"`, this must be a valid base64-encoded string.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the file. Defaults to a value inferred from the file extension when omitted.", + "example": "application/json", + "type": "string" + }, + "data_encoding": { + "description": "Encoding of `content`. `\"raw\"` (default) stores the value verbatim. `\"base64\"` decodes the value server-side before storage — use this to ship binary assets (PDFs, images) through a JSON body.", + "example": "raw", + "type": "string" + }, + "relative_path": { + "description": "Path of this file relative to the solution root (e.g. `README.md`, `assets/diagram.png`).", + "example": "README.md", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "lookup_key": { + "description": "Stable lookup key for this solution. A suffix is appended at install time to namespace the stored config.", + "example": "string", + "type": "string" + } + }, + "required": [ + "lookup_key", + "content" + ], + "type": "object" + }, + "template": { + "description": "Convenience shorthand for supplying a single template. Equivalent to setting `templates: [template]`. Mutually exclusive with `templates`. Use `templates` directly when bundling multiple sibling templates.", + "example": { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + }, + "properties": { + "content": { + "description": "Full text content of the agent template file, typically a YAML document.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the template content. Defaults to `application/x-yaml` when omitted.", + "example": "application/json", + "type": "string" + }, + "relative_path": { + "description": "Bundle-relative path to the template file, used to derive its storage identity (e.g. `\"agent.yaml\"`).", + "example": "agent.yaml", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "templates": { + "description": "Ordered list of templates the solution wraps. The first entry is the deployable template; additional entries are sibling templates it references via `template_path:`. Mutually exclusive with `template`.", + "example": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + } + ], + "items": { + "description": "The agent template definition to install. Contains the raw YAML or JSON template body whose `config_ref` entries are rewritten during installation to include the per-install suffix.", + "example": { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + }, + "properties": { + "content": { + "description": "Full text content of the agent template file, typically a YAML document.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the template content. Defaults to `application/x-yaml` when omitted.", + "example": "application/json", + "type": "string" + }, + "relative_path": { + "description": "Bundle-relative path to the template file, used to derive its storage identity (e.g. `\"agent.yaml\"`).", + "example": "agent.yaml", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "solution" + ], + "type": "object" + }, + "team": { + "description": "Team ID (`team_...`) for the import destination scope.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) for the import destination scope. Only one of `org`, `team`, or `user` may be set.", + "example": "string", + "type": "string" + }, + "virtual_path_prefix": { + "description": "Path prefix under which all uploaded configs' `virtual_path` values are anchored (for example `solutions/`). Stable per install; omit to use no prefix.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SolutionImportResponse" + } + } + }, + "description": "The imported Solution in summary form, plus `installed_configs` — one entry per config the transaction created or would create in `dry_run` mode. `installed_configs` is deprecated; prefer the `solution` summary shape for new integrations." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden — app scope required" + }, + "404": { + "description": "Solution not found" + }, + "409": { + "description": "Conflict; Solution lookup keys beginning with `designer-` are reserved for Designer Apply" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Import a Solution into the library", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/solutions/{solution}": { + "delete": { + "description": "Permanently deletes an imported Solution and all configs bundled with it,\nincluding templates, skills, scripts, and files. The deletion runs in a\nsingle transaction; provider-stored blobs are swept asynchronously after commit.\n\nOrg-scope callers (for example, an org admin in the Library settings page) can\nonly delete their org's copy of the Solution. App-scope callers can delete\nSolutions at either scope. RBAC is enforced inside the core delete flow.\n\nReturns `204 No Content` on success.\n", + "operationId": "delete_api_v1_solutions__solution", + "parameters": [ + { + "description": "Solution config ID (`cfg_...`) or `lookup_key` of the Solution to delete.", + "example": "string", + "in": "path", + "name": "solution", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty body. HTTP 204 indicates the Solution was deleted successfully." + }, + "403": { + "description": "Forbidden; App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Solution not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Delete a Solution", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns a single Solution identified by its config ID (`cfg_...`) or\n`lookup_key`, in the same summary shape the list endpoint emits. The response\nalways includes a freshly-minted `readme_url` — call this endpoint to refresh\nan expired README token without making any other state change.\n\nVisibility matches the list endpoint: app-level Solutions (no org affiliation)\nare visible to everyone — including unauthenticated callers, so the public\ncatalog can render a Solution's detail page logged-out; org-scoped Solutions\nare only visible to authenticated viewers whose org context matches. Anything\nelse returns 404.\n\nWhen the resolved Solution is org-scoped, the endpoint compares its\n`solution_version` against the matching app-level copy. If the app-level copy\nis at a higher version the response includes `upgrade_available: true` and\n`latest_version`. App-level resolutions always report `upgrade_available: false`.\n", + "operationId": "get_api_v1_solutions__solution", + "parameters": [ + { + "description": "Solution config ID (`cfg_...`) or `lookup_key` of the Solution to retrieve.", + "example": "string", + "in": "path", + "name": "solution", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SolutionSummary" + } + } + }, + "description": "Solution summary including a freshly-minted `readme_url` token valid for one hour." + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Solution not found" + } + }, + "summary": "Retrieve a Solution", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/solutions/{solution}/dependents": { + "get": { + "description": "Returns a read-only preview of what deleting the specified Solution would\naffect: the agents that reference the Solution's bundle, and the count of\nbundled configs that would be orphaned rather than cascade-deleted.\n\nUse this endpoint before calling `DELETE /api/v1/solutions/:solution` to\nsurface a warning when live agents depend on the Solution.\n\nVisibility scope mirrors the delete endpoint: org-scope viewers see their\norg's copy; app-scope viewers can inspect either scope.\n", + "operationId": "get_api_v1_solutions__solution_dependents", + "parameters": [ + { + "description": "Solution config ID (`cfg_...`) or `lookup_key` of the Solution to inspect.", + "example": "string", + "in": "path", + "name": "solution", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SolutionDependentsResponse" + } + } + }, + "description": "Agents that reference this Solution's bundle plus the count of configs that would be orphaned on delete." + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Solution not found" + } + }, + "summary": "Preview Solution delete impact", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/solutions/{solution}/image": { + "get": { + "description": "Returns the raw bytes of a Solution's cover image — the bundled asset the\nSolution body's `image:` field names — or, with the optional `file` param,\none of its gallery screenshots (`screenshots:` entries). This endpoint backs\nthe `image_url` and `screenshot_urls` fields of catalog payloads (such as\n`GET /api/v1/solutions`), which anonymous consumers — the public\nmarketplace's page cache, OpenGraph scrapers — may hold far longer than a\nsigned storage URL lives. Authorization is performed via a short, stable\ncapability `token` rather than an HTTP header, so the URL never expires.\n\nThe `token` is an HMAC-based capability tied to the Solution config ID. It\ndoes not expire, but the endpoint checks at fetch time that the Solution\nstill declares the requested image — without `file`, that it still declares\na cover; with `file`, that the path is still among the body's declared\n`image`/`screenshots` — so republishing without the asset (or hiding the\nSolution) turns the URL into a 404. Shared caches may continue serving the\nold image until the `Cache-Control` max-age of one hour elapses. `v` is an\nopaque cache key minted alongside the token; it changes when the Solution\nchanges and is ignored by verification.\n\nAll failure modes — invalid config ID, invalid token, hidden Solution, no\ndeclared cover, a `file` outside the declared set, or an asset that doesn't\nresolve to a bundled image — return a uniform `404` to avoid acting as an\nexistence oracle.\n", + "operationId": "get_api_v1_solutions__solution_image", + "parameters": [ + { + "description": "Solution config ID (`cfg_...`) whose cover image to fetch.", + "example": "string", + "in": "path", + "name": "solution", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "HMAC capability token authorizing access to this Solution's cover. Obtained from the `image_url` minted when the Solution was serialized.", + "example": "string", + "in": "query", + "name": "token", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Opaque cache key minted alongside the token; changes when the Solution changes. Ignored by token verification.", + "example": "string", + "in": "query", + "name": "v", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Bundled asset path of the image to serve (for example `images/setup.png`). Must be one of the paths the Solution body currently declares in `image`/`screenshots` — anything else is a `404`. When absent the declared cover (`image:`) is served.", + "example": "string", + "in": "query", + "name": "file", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "*/*": { + "schema": { + "format": "binary", + "type": "string" + } + } + }, + "description": "Raw cover image bytes, served with the asset's image content type." + }, + "404": { + "description": "Not found" + } + }, + "summary": "Fetch a Solution cover image or gallery screenshot" + } + }, + "/api/v1/solutions/{solution}/install": { + "post": { + "description": "Provisions a runtime resource from an already-imported Solution. The type of\nresource created depends on the template the Solution wraps: an\n`AgentTemplate` produces an Agent, an `AutomationTemplate` produces an\nAutomation, and attachment templates (`AgentRoutineTemplate`,\n`AgentToolTemplate`, `AgentSkillTemplate`, `AgentComputerTemplate`) attach a\nsub-resource to an existing Agent specified by `target`.\n\nFor Solutions that bundle more than one template, pass `template` (the ID or\n`lookup_key` of the desired template) to select which one to provision.\nSingle-template Solutions do not require `template`.\n\nPairs with `POST /api/v1/solutions` (import): import puts the Solution into\nthe library; install provisions a runtime resource from it.\n", + "operationId": "post_api_v1_solutions__solution_install", + "parameters": [ + { + "description": "Config ID (`cfg_...`) or `lookup_key` of the already-imported Solution to install from.", + "example": "string", + "in": "path", + "name": "solution", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "allow_auto_import": true, + "install_inputs": {}, + "lookup_key": "string", + "lookup_key_suffix": "string", + "name": "Example Name", + "org": "string", + "target": "string", + "team": "string", + "template": "string", + "user": "string" + }, + "properties": { + "acl": { + "description": "Access control list applied atomically to a provisioned Agent or Automation. Team grants are useful when installing into a cross-organization collaboration team.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "allow_auto_import": { + "description": "When `true`, automatically imports the Solution into the target tenant before installing if the org-scoped copy does not yet exist. Requires either an authenticated org user (member or admin) or a platform-privileged caller (S2S, developer JWT) that also supplies an explicit `org` param. Defaults to `false`; without it the endpoint returns 404 when the org-scoped Solution is missing.", + "example": true, + "type": "boolean" + }, + "details": { + "description": "Template-specific install options selected by the `type` discriminator. AutomationTemplate installs accept `{type: \"automation\", prefills: ...}`.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific options for a Solution install.", + "example": { + "prefills": { + "participants": {}, + "payload": {} + }, + "type": "automation" + }, + "properties": { + "prefills": { + "description": "Instance-specific locked payload and participant values. Payload paths and participant slots are validated against the installed template's resolved input schema and workflow.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + }, + "type": { + "default": "automation", + "description": "Install-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "install_inputs": { + "description": "Values applied to parameterized AgentTemplate prose during a root Agent install. Use `{values: {customer_label: \"Acme\"}}`.", + "example": {}, + "type": "object" + }, + "lookup_key": { + "description": "Lookup key override for the provisioned resource (for example, the Agent's `agent_key`).", + "example": "string", + "type": "string" + }, + "lookup_key_suffix": { + "description": "Suffix appended to every `config_ref:` resolution at install time. Should be stable per logical install and unique per attempt — allows the same Solution to be installed multiple times in the same app without collisions.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Display name override for a provisioned Agent or Automation. Ignored for attachment Solutions.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) for the install destination scope.", + "example": "string", + "type": "string" + }, + "target": { + "description": "ID or `lookup_key` of the parent Agent to attach to. Required when installing an `AgentRoutineTemplate`, `AgentToolTemplate`, `AgentSkillTemplate`, or `AgentComputerTemplate` Solution, since those produce sub-resources attached to an existing Agent. Omit for `AgentTemplate` and `AutomationTemplate` Solutions, which provision standalone resources.", + "example": "string", + "type": "string" + }, + "team": { + "description": "Team ID (`team_...`) for the install destination scope.", + "example": "string", + "type": "string" + }, + "template": { + "description": "Config ID (`cfg_...`) or `lookup_key` of the template within the Solution to provision. Required when the Solution bundles more than one template; omit for single-template Solutions, where the only template is selected implicitly.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) for the install destination scope.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SolutionInstallResponse" + } + } + }, + "description": "The provisioned runtime resource (Agent, Automation, AgentRoutine, AgentTool, AgentSkill, or AgentComputer) together with the source Solution's config ID." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden — app scope required" + }, + "404": { + "description": "Solution not found" + }, + "409": { + "description": "Conflict; Solution lookup keys beginning with `designer-` are reserved for Designer Apply" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Install a Solution", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/solutions/{solution}/readme": { + "get": { + "description": "Serves the README markdown or a bundled asset for an imported Solution. Both\nmodes use the same path and require a short-lived signed `token` in the query\nstring rather than an `Authorization` header, so browsers can load asset URLs\ndirectly from `` attributes without custom request logic.\n\nWhen `file` is omitted the response is the Solution's `readme` field rendered\nas `text/markdown`. All local asset references in the markdown are rewritten to\npoint back at this endpoint with `?file=PATH&token=TOKEN` so browsers can load\nimages inline without additional authentication.\n\nWhen `file` is set the response is the raw bytes of the matching asset (a File\nchild whose `relative_path` equals `PATH`, or an inline `assets` entry by\nname) with the asset's stored `Content-Type`.\n\nTokens are scoped to a single Solution, carry the viewer's app, org, and\nsandbox context from the time they were minted, and expire after one hour.\nObtain a fresh token by calling `GET /api/v1/solutions/:solution`, which\nalways returns a newly minted `readme_url`.\n", + "operationId": "get_api_v1_solutions__solution_readme", + "parameters": [ + { + "description": "Solution config ID (`cfg_...`) identifying the Solution whose README or asset to retrieve.", + "example": "string", + "in": "path", + "name": "solution", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Signed URL token minted by the list or show endpoint. Expires after one hour.", + "example": "string", + "in": "query", + "name": "token", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Relative path of the asset to retrieve (for example `images/hero.png`). When present the response is the raw asset bytes with its real `Content-Type`; when absent the response is the README markdown.", + "example": "string", + "in": "query", + "name": "file", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "*/*": { + "schema": { + "format": "binary", + "type": "string" + } + } + }, + "description": "README markdown (`text/markdown`) when `file` is omitted, or the raw asset bytes with the asset's `Content-Type` when `file` is set." + }, + "401": { + "description": "Invalid or expired signed URL token" + }, + "404": { + "description": "Solution not found; README not found for this Solution; File not found" + } + }, + "summary": "Retrieve a Solution README or asset" + } + }, + "/api/v1/solutions/{solution}/upgrade": { + "post": { + "description": "Applies an incoming bundle to an already-installed Solution in a single atomic\ntransaction, bringing its configs in line with the new bundle. Config IDs are\npreserved across the upgrade. Configs that existed in the old bundle but are\nabsent from the new one are orphaned (top-level) or hard-deleted (child rows).\n\nTwo mutually exclusive source modes: pass `target_solution` to pull the\nincoming bundle from an existing Solution by ID or `lookup_key`, or pass\n`solution_bundle` to supply a complete inline bundle directly. Exactly one\nmust be present.\n\nWhen `dry_run` is `true` the full diff is computed and returned but no\nchanges are written. Pass the dry-run response's `review_fingerprint` as\n`expected_review_fingerprint` when applying to guard against the bundle\nchanging between review and apply.\n", + "operationId": "post_api_v1_solutions__solution_upgrade", + "parameters": [ + { + "description": "Config ID (`cfg_...`) or `lookup_key` of the currently installed Solution to upgrade.", + "example": "string", + "in": "path", + "name": "solution", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "allow_downgrade": true, + "dry_run": true, + "expected_review_fingerprint": "string", + "org": "string", + "solution_bundle": { + "configs": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "tools/my-tool.yaml" + } + ], + "lookup_key_prefix": "string", + "lookup_key_suffix": "string", + "setup_actions": [ + { + "depends_on": [ + "string" + ], + "description": "An example description.", + "kind": "env_var", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "title": "Example Title", + "verify_config": { + "key": "value" + } + } + ], + "skills": [ + { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "relative_path": "skills/my-skill/SKILL.md" + } + ], + "solution": { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "data_encoding": "raw", + "relative_path": "README.md" + } + ], + "lookup_key": "string" + }, + "template": { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + }, + "templates": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + } + ] + }, + "target_solution": "string" + }, + "properties": { + "allow_downgrade": { + "description": "When `true`, permits an incoming `solution_version` lower than the currently installed version. Defaults to `false`.", + "example": true, + "type": "boolean" + }, + "dry_run": { + "description": "When `true`, computes and returns the full upgrade diff without persisting any changes. Defaults to `false`.", + "example": true, + "type": "boolean" + }, + "expected_review_fingerprint": { + "description": "Optional stale-review guard. Pass the `review_fingerprint` returned by a prior `dry_run` call to ensure the bundle has not changed between review and apply.", + "example": "string", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) used to resolve org-scoped `lookup_key` values. Config IDs (`cfg_...`) are globally unique and do not require this.", + "example": "string", + "type": "string" + }, + "solution_bundle": { + "description": "Complete inline bundle for a direct upgrade, including Solution metadata, templates, skills, configs, files, and setup actions. Mutually exclusive with `target_solution`.", + "example": { + "configs": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "tools/my-tool.yaml" + } + ], + "lookup_key_prefix": "string", + "lookup_key_suffix": "string", + "setup_actions": [ + { + "depends_on": [ + "string" + ], + "description": "An example description.", + "kind": "env_var", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "title": "Example Title", + "verify_config": { + "key": "value" + } + } + ], + "skills": [ + { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "relative_path": "skills/my-skill/SKILL.md" + } + ], + "solution": { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "data_encoding": "raw", + "relative_path": "README.md" + } + ], + "lookup_key": "string" + }, + "template": { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + }, + "templates": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + } + ] + }, + "properties": { + "configs": { + "description": "Additional configs of any kind that the solution.yaml references and that should be upserted as part of this install.", + "example": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "tools/my-tool.yaml" + } + ], + "items": { + "description": "A supporting configuration resource included in a template bundle, such as a script, model config, or routine template referenced by the agent template.", + "example": { + "content": "string", + "content_type": "application/json", + "relative_path": "tools/my-tool.yaml" + }, + "properties": { + "content": { + "description": "Full text content of the configuration file.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the configuration content, e.g. `\"application/x-yaml\"` or `\"application/json\"`. `null` if not specified.", + "example": "application/json", + "type": "string" + }, + "relative_path": { + "description": "Bundle-relative path to this config file. The path determines the config kind and its storage identity within the installation.", + "example": "tools/my-tool.yaml", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "lookup_key_prefix": { + "description": "String prepended (with a `-` separator) to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Typical value is `solutions-`.", + "example": "string", + "type": "string" + }, + "lookup_key_suffix": { + "description": "String appended to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Should be stable for a given install and unique per attempt.", + "example": "string", + "type": "string" + }, + "setup_actions": { + "description": "Post-install setup checklist items for the wrapped template. Allowed only when the bundle contains a single template and that template's body does not already declare its own `setup_actions`. Omit when bundling multiple templates.", + "example": [ + { + "depends_on": [ + "string" + ], + "description": "An example description.", + "kind": "env_var", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "title": "Example Title", + "verify_config": { + "key": "value" + } + } + ], + "items": { + "description": "A post-install setup checklist item that the user must complete before the installed agent is fully operational.", + "example": { + "depends_on": [ + "string" + ], + "description": "An example description.", + "kind": "env_var", + "params": { + "key": "value" + }, + "required": true, + "sort_order": 1, + "title": "Example Title", + "verify_config": { + "key": "value" + } + }, + "properties": { + "depends_on": { + "description": "List of other setup action identifiers that must be completed before this action becomes actionable.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "description": { + "description": "Markdown-formatted instructions or context shown beneath the checklist item. `null` if not provided.", + "example": "An example description.", + "type": "string" + }, + "kind": { + "description": "Category of setup step. One of `\"env_var\"` (configure an environment variable), `\"install\"` (complete an installation step), `\"custom\"` (a user-defined action), or `\"integration\"` (authorize an OAuth-backed MCP server integration).", + "example": "env_var", + "type": "string" + }, + "params": { + "description": "Kind-specific configuration for the action. For `\"env_var\"` steps this typically includes `key` and `scope`; for `\"install\"` steps it includes `installation_kind`; for `\"integration\"` steps it includes `mcp_server_ref`. Shape varies by `kind`.", + "example": { + "key": "value" + }, + "type": "object" + }, + "required": { + "description": "When `true`, this action must be completed before the checklist progress bar reaches 100%. Defaults to `true`.", + "example": true, + "type": "boolean" + }, + "sort_order": { + "description": "Numeric sort position controlling the display order of this action in the checklist. Defaults to `0` when not specified.", + "example": 1, + "type": "integer" + }, + "title": { + "description": "Short human-readable label displayed in the setup checklist.", + "example": "Example Title", + "type": "string" + }, + "verify_config": { + "description": "Configuration passed to the runtime verifier to determine whether the action has been completed, e.g. `{\"type\": \"secret_present\"}`. `null` if no automated verification is configured.", + "example": { + "key": "value" + }, + "type": "object" + } + }, + "required": [ + "kind", + "title" + ], + "type": "object" + }, + "type": "array" + }, + "skills": { + "description": "Skill bundles (root config plus supporting files) that this solution depends on.", + "example": [ + { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "relative_path": "skills/my-skill/SKILL.md" + } + ], + "items": { + "description": "A skill to install as part of a template bundle, consisting of a root `SKILL.md` definition and any accompanying support files.", + "example": { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "relative_path": "skills/my-skill/SKILL.md" + }, + "properties": { + "content": { + "description": "Full text content of the `SKILL.md` file.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the `SKILL.md` content. Defaults to `text/markdown` when omitted.", + "example": "application/json", + "type": "string" + }, + "files": { + "description": "Additional files nested inside the skill folder, each with its own path and content.", + "example": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + } + ], + "items": { + "description": "A single file nested inside a skill folder, included as part of an install bundle.", + "example": { + "content": "string", + "content_type": "application/json", + "relative_path": "skills/my-skill/helpers.md" + }, + "properties": { + "content": { + "description": "Full text content of the file.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the file content. Defaults to a value inferred from the file extension when omitted.", + "example": "application/json", + "type": "string" + }, + "relative_path": { + "description": "Path of this file relative to the skill folder root, e.g. `\"skills/my-skill/helpers.md\"`.", + "example": "skills/my-skill/helpers.md", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "relative_path": { + "description": "Bundle-relative path to the skill root, which must end in `/SKILL.md` (e.g. `\"skills/my-skill/SKILL.md\"`).", + "example": "skills/my-skill/SKILL.md", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "solution": { + "description": "The solution config to install, including the solution.yaml body and any referenced component files.", + "example": { + "content": "string", + "content_type": "application/json", + "files": [ + { + "content": "string", + "content_type": "application/json", + "data_encoding": "raw", + "relative_path": "README.md" + } + ], + "lookup_key": "string" + }, + "properties": { + "content": { + "description": "Raw solution.yaml body (YAML or JSON). Describes the solution structure, template references, and asset declarations.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of `content`. Defaults to `application/x-yaml`; pass `application/json` when submitting JSON.", + "example": "application/json", + "type": "string" + }, + "files": { + "description": "Component files (READMEs, diagrams, fixtures) referenced by the solution.yaml via `path://` URIs. Each entry is persisted as a child file record.", + "example": [ + { + "content": "string", + "content_type": "application/json", + "data_encoding": "raw", + "relative_path": "README.md" + } + ], + "items": { + "description": "A component file included in a solution bundle, such as a README, diagram, or fixture referenced by the solution.yaml via a `path://` URI.", + "example": { + "content": "string", + "content_type": "application/json", + "data_encoding": "raw", + "relative_path": "README.md" + }, + "properties": { + "content": { + "description": "Raw content of the file. When `data_encoding` is `\"base64\"`, this must be a valid base64-encoded string.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the file. Defaults to a value inferred from the file extension when omitted.", + "example": "application/json", + "type": "string" + }, + "data_encoding": { + "description": "Encoding of `content`. `\"raw\"` (default) stores the value verbatim. `\"base64\"` decodes the value server-side before storage — use this to ship binary assets (PDFs, images) through a JSON body.", + "example": "raw", + "type": "string" + }, + "relative_path": { + "description": "Path of this file relative to the solution root (e.g. `README.md`, `assets/diagram.png`).", + "example": "README.md", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "lookup_key": { + "description": "Stable lookup key for this solution. A suffix is appended at install time to namespace the stored config.", + "example": "string", + "type": "string" + } + }, + "required": [ + "lookup_key", + "content" + ], + "type": "object" + }, + "template": { + "description": "Convenience shorthand for supplying a single template. Equivalent to setting `templates: [template]`. Mutually exclusive with `templates`. Use `templates` directly when bundling multiple sibling templates.", + "example": { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + }, + "properties": { + "content": { + "description": "Full text content of the agent template file, typically a YAML document.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the template content. Defaults to `application/x-yaml` when omitted.", + "example": "application/json", + "type": "string" + }, + "relative_path": { + "description": "Bundle-relative path to the template file, used to derive its storage identity (e.g. `\"agent.yaml\"`).", + "example": "agent.yaml", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "templates": { + "description": "Ordered list of templates the solution wraps. The first entry is the deployable template; additional entries are sibling templates it references via `template_path:`. Mutually exclusive with `template`.", + "example": [ + { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + } + ], + "items": { + "description": "The agent template definition to install. Contains the raw YAML or JSON template body whose `config_ref` entries are rewritten during installation to include the per-install suffix.", + "example": { + "content": "string", + "content_type": "application/json", + "relative_path": "agent.yaml" + }, + "properties": { + "content": { + "description": "Full text content of the agent template file, typically a YAML document.", + "example": "string", + "type": "string" + }, + "content_type": { + "description": "MIME type of the template content. Defaults to `application/x-yaml` when omitted.", + "example": "application/json", + "type": "string" + }, + "relative_path": { + "description": "Bundle-relative path to the template file, used to derive its storage identity (e.g. `\"agent.yaml\"`).", + "example": "agent.yaml", + "type": "string" + } + }, + "required": [ + "relative_path", + "content" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "solution" + ], + "type": "object" + }, + "target_solution": { + "description": "Config ID (`cfg_...`) or `lookup_key` of the Solution to use as the incoming upgrade source. Mutually exclusive with `solution_bundle`.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SolutionUpgradeResponse" + } + } + }, + "description": "Updated Solution plus the full upgrade diff." + }, + "400": { + "description": "Bad request" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Solution not found" + }, + "409": { + "description": "Solution version downgrade is not allowed; Incoming Solution identity does not match the Solution being updated; Solution changed since review; prepare the diff again.; Solution lookup keys beginning with `designer-` are reserved for Designer Apply" + }, + "422": { + "description": "Inline-template Solutions cannot be updated; Validation failed" + } + }, + "summary": "Upgrade an installed Solution", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/solutions/{solution}/view": { + "post": { + "description": "Records a `solution_viewed` analytics event for the identified Solution and\nreturns `204 No Content`. Fired by the marketplace when a Solution's detail\npage is rendered in a browser, so publishers can see impressions alongside\ninstalls in their Solution analytics.\n\nVisibility matches `GET /api/v1/solutions/:solution`: unauthenticated callers\n(the logged-out marketplace) can only track Solutions published to the public\ncatalog; anything the caller could not retrieve returns 404 and records\nnothing.\n\nPass `anonymous` (the analytics visitor ID) so logged-out views can be\ncounted as unique viewers. The event's Solution and publisher attribution are\nresolved server-side from the Solution row — never from request input.\n", + "operationId": "post_api_v1_solutions__solution_view", + "parameters": [ + { + "description": "Solution config ID (`cfg_...`) or `lookup_key` of the viewed Solution.", + "example": "string", + "in": "path", + "name": "solution", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "anonymous": "string" + }, + "properties": { + "anonymous": { + "description": "Analytics visitor ID to attribute the view to, for unique-viewer counting. Same identifier the `POST /api/v1/t` events use; the marketplace sends it on every view. Authenticated callers additionally get user attribution from their session.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Empty body. HTTP 204 indicates the Solution view was recorded successfully." + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Solution not found" + } + }, + "summary": "Track a Solution detail-page view", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/status/ping": { + "get": { + "description": "Returns the validity and metadata of the bearer token supplied in the request.\nUse this endpoint to verify that an API key or session token is present, active,\nand unexpired before making authenticated calls.\n\nNo authentication is required to call this endpoint — it accepts any request,\nincluding those with no token at all. When a token is absent the `token.status`\nfield is `\"missing\"` and `token.active` is `false`. When a token is present but\ninvalid (expired, malformed, or referencing an unknown user) `token.active` is\n`false` and `token.status` describes the failure reason. When the token is valid,\n`token.active` is `true`, `token.status` is `\"active\"`, and `user` is populated\nwith the authenticated user's profile.\n", + "operationId": "get_api_v1_status_ping", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatusPing" + } + } + }, + "description": "Token validity details and, when the token is active, the authenticated user's profile." + } + }, + "summary": "Check API token status", + "x-auth": [ + "publishable_key" + ] + } + }, + "/api/v1/tasks/{task}": { + "delete": { + "description": "Deletes a task from task lists and detail views. The task event stream is\nretained for auditability, while comments are removed and direct subtasks\nare promoted to top-level tasks.\n\nThe delete event is accepted before the read model is updated. Clients\nshould remove the task from local collections immediately; subsequent reads\nconverge once the projection processes the event.\n\nAuthenticated users may delete tasks they can access using their session\nidentity. App-scoped developer and server-to-server callers must explicitly\nsupply the task's `org` and owner. `team` or `user` identifies that owner;\nwhen neither is present, `agent` identifies an agent-owned task. With a team\nor user owner, `agent` identifies the acting principal. Each reference is\nvalidated before deletion.\n", + "operationId": "delete_api_v1_tasks__task", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response. HTTP 204 is returned after the delete event is accepted." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Delete a task", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the full task object for the specified task ID. Authenticated users\nand agents resolve access through their session. App-scoped developer and\nserver-to-server callers explicitly provide the owning `team`, `user`, or `agent` and\n`org`. Callers without access receive a 404.\n", + "operationId": "get_api_v1_tasks__task", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning team (`tem_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning user (`usr_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning agent (`agi_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit organization (`org_...`) for privileged calls; pass null when unscoped.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Task" + } + } + }, + "description": "The requested task." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Retrieve a task", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "put": { + "description": "Updates the supplied fields on a task and returns the complete updated task.\nAuthenticated users use their session identity. App-scoped developer and\nserver-to-server callers must explicitly supply the task's `org` and owner.\n`team` or `user` identifies that owner; when neither is present, `agent`\nidentifies an agent-owned task. With a team or user owner, `agent` identifies\nthe acting principal. Every reference is validated before the update.\n\nA cooperating coding-session client may supply both `lease_id` and\n`lease_session_id`. The task aggregate fences that update against the live\nlease and records server-sourced session provenance. Omitting both remains a\nnormal authorized human/API update.\n", + "operationId": "put_api_v1_tasks__task", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "lease_id": "string", + "lease_session_id": "string", + "links": {}, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "string", + "owner_agent": "string", + "owner_user": "string", + "parent": "string", + "priority": 1, + "status": "string", + "tags": [ + "string" + ], + "team": "string", + "user": "string" + }, + "properties": { + "agent": { + "description": "Explicit agent (`agi_...`). It is the owner when `team` and `user` are absent; otherwise it is the acting principal.", + "example": "string", + "type": "string" + }, + "description": { + "description": "Updated long-form description.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Updated due date in ISO 8601 format, or null to clear it.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "lease_id": { + "description": "Current caller-held lease UUID. Must be paired with `lease_session_id`.", + "example": "string", + "type": "string" + }, + "lease_session_id": { + "description": "Current coding-session UUID. Must be paired with `lease_id`.", + "example": "string", + "type": "string" + }, + "links": { + "description": "Replacement related-links object.", + "example": {}, + "type": "object" + }, + "metadata": { + "description": "Replacement task metadata object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Updated display name for the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Explicit organization (`org_...`) for a developer or server-to-server call. Pass null for an owner outside an organization.", + "example": "string", + "type": "string" + }, + "owner_agent": { + "description": "Assign to an agent by public ID (`agi_...`).", + "example": "string", + "type": "string" + }, + "owner_user": { + "description": "Assign to a user by public ID (`usr_...`).", + "example": "string", + "type": "string" + }, + "parent": { + "description": "Move this task under a top-level parent (`tsk_...`), or pass null to promote it to a top-level task. A task that has subtasks cannot become one.", + "example": "string", + "type": "string" + }, + "priority": { + "description": "Updated priority from 0 (highest) to 4 (lowest).", + "example": 1, + "type": "integer" + }, + "status": { + "description": "Updated status: `open`, `in_progress`, or `done`.", + "example": "string", + "type": "string" + }, + "tags": { + "description": "Replacement tag list (max 20, each up to 40 characters; normalized to lowercase). Pass an empty array to clear all tags.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "Explicit owning team (`tem_...`) for a developer or server-to-server call.", + "example": "string", + "type": "string" + }, + "user": { + "description": "Explicit user (`usr_...`) for a developer or server-to-server call. With `team`, this identifies the acting team member.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Task" + } + } + }, + "description": "The updated task." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Task is not assigned to the authenticated user" + }, + "404": { + "description": "Task not found" + }, + "409": { + "description": "Task lease has expired; Task lease does not match the current holder" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Update a task", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/tasks/{task}/activity": { + "get": { + "description": "Returns a bounded chronological page of activity for the specified task.\nApp-scoped developer and server-to-server callers explicitly provide the\nowning `team`, `user`, or `agent` and `org`.\n", + "operationId": "get_api_v1_tasks__task_activity", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning team (`tem_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning user (`usr_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning agent (`agi_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit organization (`org_...`) for privileged calls; pass null when unscoped.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum entries to return. Capped at 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the previous page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Activity history for the task.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "event_type": "task.status_changed", + "sentence": "Alice changed the status to in_progress.", + "timestamp": "2024-01-01T00:00:00Z" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "data": { + "example": [ + { + "event_type": "task.status_changed", + "sentence": "Alice changed the status to in_progress.", + "timestamp": "2024-01-01T00:00:00Z" + } + ], + "items": { + "description": "A single activity event recorded against a task, with a pre-rendered sentence describing what occurred.", + "example": { + "event_type": "task.status_changed", + "sentence": "Alice changed the status to in_progress.", + "timestamp": "2024-01-01T00:00:00Z" + }, + "properties": { + "event_type": { + "description": "Machine-readable type of the event, e.g. `\"task.status_changed\"` or `\"task.comment_added\"`.", + "example": "task.status_changed", + "type": "string" + }, + "sentence": { + "description": "Human-readable sentence describing the activity, suitable for display in an activity feed.", + "example": "Alice changed the status to in_progress.", + "type": "string" + }, + "timestamp": { + "description": "When this activity event occurred (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "has_more": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "List a task's activity", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/tasks/{task}/blockers": { + "get": { + "description": "Returns a bounded page of the tasks currently marked as blocking the\nspecified task, newest first. Blocking is informational: a blocked task\ncan still change status, and it stops counting as blocked as soon as\nevery blocker is done. The task's owner is resolved from the task itself.\n", + "operationId": "get_api_v1_tasks__task_blockers", + "parameters": [ + { + "description": "Blocked task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning team (`tem_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning user (`usr_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning agent (`agi_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit organization (`org_...`) for privileged calls; pass null when unscoped.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum blockers to return. Capped at 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the previous page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Tasks blocking the task.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "data": { + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A task representing a unit of work, optionally assignable to a user or agent.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "blocked_by_count": { + "description": "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind.", + "example": 1, + "type": "integer" + }, + "closed_at": { + "description": "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "comments_count": { + "description": "Total number of comments posted on this task.", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the task was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by_actor": { + "description": "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "created_by_agent": { + "description": "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_by_user": { + "description": "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "current_lease": { + "description": "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "nullable": true, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the coding session.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the coding session that holds the lease.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "session_name", + "harness", + "expires_at" + ], + "type": "object" + }, + "description": { + "description": "Long-form description or notes for the task. `null` if no description has been provided.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Task ID (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_blocked": { + "description": "`true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read.", + "example": true, + "type": "boolean" + }, + "links": { + "description": "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title of the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_actor": { + "description": "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "owner_agent": { + "description": "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_user": { + "description": "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level.", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "priority": { + "description": "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set.", + "example": 2, + "type": "integer" + }, + "sandbox": { + "description": "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`.", + "example": "open", + "type": "string" + }, + "subtasks_count": { + "description": "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.", + "example": 1, + "type": "integer" + }, + "tags": { + "description": "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the task was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "List a task's blockers", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Records that the task in `blocker` blocks the specified task and returns\nthe updated task. Blocking is informational — the blocked task can still\nchange status — and derived at read time, so the task stops reporting\n`is_blocked` as soon as every blocker is done. The blocker must belong to\nthe same owner (team or user) as the task; self-blocking and blocking a\ntask that already blocks the blocker (a direct cycle) are rejected.\n", + "operationId": "post_api_v1_tasks__task_blockers", + "parameters": [ + { + "description": "Task ID to mark as blocked (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "blocker": "string", + "org": "string", + "team": "string", + "user": "string" + }, + "properties": { + "agent": { + "description": "Explicit owning agent (`agi_...`) for privileged calls.", + "example": "string", + "type": "string" + }, + "blocker": { + "description": "ID of the task that blocks this task (`tsk_...`).", + "example": "string", + "type": "string" + }, + "org": { + "description": "Explicit organization (`org_...`) for privileged calls; pass null when unscoped.", + "example": "string", + "type": "string" + }, + "team": { + "description": "Explicit owning team (`tem_...`) for privileged calls.", + "example": "string", + "type": "string" + }, + "user": { + "description": "Explicit owning user (`usr_...`) for privileged calls.", + "example": "string", + "type": "string" + } + }, + "required": [ + "blocker" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Task" + } + } + }, + "description": "The updated (blocked) task." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Mark a task as blocked by another task", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/tasks/{task}/blockers/{blocker}": { + "delete": { + "description": "Removes the blocking relationship between the task in `blocker` and the\nspecified task. Returns 204 No Content on success, or 404 if the given\ntask is not currently marked as blocking this task.\n", + "operationId": "delete_api_v1_tasks__task_blockers__blocker", + "parameters": [ + { + "description": "Blocked task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "ID of the blocking task to remove (`tsk_...`).", + "example": "string", + "in": "path", + "name": "blocker", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response body. HTTP 204 No Content on success." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task not found; Resource not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Remove a blocker from a task", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/tasks/{task}/blocking": { + "get": { + "description": "Returns a bounded page of the tasks that the specified task is marked as\nblocking (the inverse of `GET /tasks/{task}/blockers`), newest first.\nThe task's owner is resolved from the task itself.\n", + "operationId": "get_api_v1_tasks__task_blocking", + "parameters": [ + { + "description": "Blocking task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning team (`tem_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning user (`usr_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning agent (`agi_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit organization (`org_...`) for privileged calls; pass null when unscoped.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum tasks to return. Capped at 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the previous page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Tasks blocked by the task.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "data": { + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A task representing a unit of work, optionally assignable to a user or agent.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "blocked_by_count": { + "description": "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind.", + "example": 1, + "type": "integer" + }, + "closed_at": { + "description": "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "comments_count": { + "description": "Total number of comments posted on this task.", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the task was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by_actor": { + "description": "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "created_by_agent": { + "description": "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_by_user": { + "description": "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "current_lease": { + "description": "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "nullable": true, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the coding session.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the coding session that holds the lease.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "session_name", + "harness", + "expires_at" + ], + "type": "object" + }, + "description": { + "description": "Long-form description or notes for the task. `null` if no description has been provided.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Task ID (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_blocked": { + "description": "`true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read.", + "example": true, + "type": "boolean" + }, + "links": { + "description": "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title of the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_actor": { + "description": "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "owner_agent": { + "description": "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_user": { + "description": "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level.", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "priority": { + "description": "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set.", + "example": 2, + "type": "integer" + }, + "sandbox": { + "description": "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`.", + "example": "open", + "type": "string" + }, + "subtasks_count": { + "description": "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.", + "example": 1, + "type": "integer" + }, + "tags": { + "description": "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the task was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "List the tasks a task blocks", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/tasks/{task}/comments": { + "get": { + "description": "Returns a bounded page of comments on the specified task, ordered by creation\ntime ascending. App-scoped developer and server-to-server callers explicitly\nprovide the owning `team`, `user`, or `agent` and `org`.\n", + "operationId": "get_api_v1_tasks__task_comments", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning team (`tem_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning user (`usr_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning agent (`agi_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit organization (`org_...`) for privileged calls; pass null when unscoped.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum comments to return. Capped at 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the previous page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Comments for the task.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "author_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "author_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "author_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "body": "Please review the latest changes and let me know if anything looks off.", + "created_at": "2024-01-01T00:00:00Z", + "id": "tcm_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "task": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "data": { + "example": [ + { + "author_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "author_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "author_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "body": "Please review the latest changes and let me know if anything looks off.", + "created_at": "2024-01-01T00:00:00Z", + "id": "tcm_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "task": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z" + } + ], + "items": { + "description": "A comment posted on a task by a user or an agent, including resolved author information.", + "example": { + "author_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "author_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "author_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "body": "Please review the latest changes and let me know if anything looks off.", + "created_at": "2024-01-01T00:00:00Z", + "id": "tcm_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "task": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "author_actor": { + "description": "Resolved author details including `id`, `name`, `alias`, and `profile_picture`. `null` if no author is set or the author cannot be resolved (e.g. authoring agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "author_agent": { + "description": "ID of the agent that posted this comment (`agi_...`). `null` if the author is a human user, or if the authoring agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "author_user": { + "description": "ID of the user who posted this comment (`usr_...`). `null` if the author is an agent, or if author provenance was cleared after the authoring agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "body": { + "description": "Plain-text body of the comment.", + "example": "Please review the latest changes and let me know if anything looks off.", + "type": "string" + }, + "created_at": { + "description": "When this comment was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Comment ID (`tcmt_...`).", + "example": "tcm_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org": { + "description": "ID of the organization that owns this comment (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Sandbox ID this comment is scoped to. `null` for comments outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "task": { + "description": "ID of the task this comment belongs to (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "team": { + "description": "ID of the team the task belongs to (`tem_...`). `null` if not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When this comment was last edited (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "body" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "List comments on a task", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Posts a new comment on the specified task and returns the created comment.\nThe task's owner is resolved from the task itself.\n", + "operationId": "post_api_v1_tasks__task_comments", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "comment": { + "body": "Looks good to me, ready for review." + } + }, + "properties": { + "comment": { + "description": "Parameters for the comment to create, including its body.", + "example": { + "body": "Looks good to me, ready for review." + }, + "properties": { + "body": { + "description": "The plain-text content of the comment. Must be a non-empty string.", + "example": "Looks good to me, ready for review.", + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + }, + "required": [ + "comment" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskComment" + } + } + }, + "description": "The newly created comment." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Create a comment on a task", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/tasks/{task}/comments/{comment}": { + "delete": { + "description": "Permanently removes a comment from its task. This action cannot be undone.\nThe task's owner is resolved from the task itself.\n\nOnly the comment's author, an admin of the comment's organization, or an\nadmin of the owning team may delete a comment. Returns `403 Forbidden`\notherwise.\n", + "operationId": "delete_api_v1_tasks__task_comments__comment", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Comment ID (`tcm_...`).", + "example": "string", + "in": "path", + "name": "comment", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty body. The server responds with HTTP 204 No Content on success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Task not found; Resource not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Delete a task comment", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "put": { + "description": "Replaces the body of an existing comment and returns the updated comment.\nThe task's owner is resolved from the task itself.\n\nOnly the comment's author, an admin of the comment's organization, or an\nadmin of the owning team may edit a comment. Returns `403 Forbidden`\notherwise.\n", + "operationId": "put_api_v1_tasks__task_comments__comment", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Comment ID (`tcm_...`).", + "example": "string", + "in": "path", + "name": "comment", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "body": "string" + }, + "properties": { + "body": { + "description": "Replacement body for the comment. Must be non-empty.", + "example": "string", + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskComment" + } + } + }, + "description": "The updated comment." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Task not found; Resource not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Update a task comment", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/tasks/{task}/lease": { + "delete": { + "description": "Releases the authenticated assignee's matching live task lease. Repeating a\nrelease after the lease is absent succeeds. A different live successor lease\nreturns a mismatch.\n", + "operationId": "delete_api_v1_tasks__task_lease", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response. HTTP 204 is returned after release is accepted." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Task is not assigned to the authenticated user" + }, + "404": { + "description": "Task not found" + }, + "409": { + "description": "Task lease has expired; Task lease does not match the current holder" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Release a task session lease", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the authenticated assignee's viewer-safe live lease summary, or null\nwhen no live lease exists. Fencing and opaque session identifiers are never\nincluded.\n", + "operationId": "get_api_v1_tasks__task_lease", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TaskSessionLeaseSummary" + } + ], + "nullable": true + } + } + }, + "description": "Viewer-safe live lease summary, or null." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Task is not assigned to the authenticated user" + }, + "404": { + "description": "Task not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Retrieve a task's current session lease", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Atomically claims a user-assigned task for the authenticated user's coding\nsession. The caller generates and retains both UUIDs. An exact retry returns\nthe existing lease without extending it; another live holder produces a\nconflict. Developer and server-to-server credentials cannot impersonate the\nassigned user.\n", + "operationId": "post_api_v1_tasks__task_lease", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "harness": "string", + "lease_duration_seconds": 1, + "lease_id": "string", + "require_ready": true, + "session_id": "string", + "session_name": "Example Name" + }, + "properties": { + "harness": { + "description": "Bounded harness identifier.", + "example": "string", + "type": "string" + }, + "lease_duration_seconds": { + "default": 300, + "description": "Requested lease lifetime in seconds; the task aggregate enforces its bounds.", + "example": 1, + "type": "integer" + }, + "lease_id": { + "description": "Caller-generated lease UUID.", + "example": "string", + "type": "string" + }, + "require_ready": { + "default": false, + "description": "Conservatively reject the claim when the current task projection has unfinished blockers.", + "example": true, + "type": "boolean" + }, + "session_id": { + "description": "Caller-generated coding-session UUID.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Human-readable coding-session label.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "lease_id", + "session_id", + "session_name", + "harness" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskSessionLease" + } + } + }, + "description": "The caller-held lease, including its fencing token." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Task is not assigned to the authenticated user" + }, + "404": { + "description": "Task not found" + }, + "409": { + "description": "Task is leased by another coding session; Task lease has expired" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Claim a task for a coding session", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/tasks/{task}/lease/renew": { + "post": { + "description": "Renews the authenticated assignee's matching live task lease. Both\ncaller-generated UUIDs must match the aggregate's current lease.\n", + "operationId": "post_api_v1_tasks__task_lease_renew", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "lease_duration_seconds": 1, + "lease_id": "string", + "session_id": "string" + }, + "properties": { + "lease_duration_seconds": { + "default": 300, + "description": "Requested renewed lifetime in seconds; the task aggregate enforces its bounds.", + "example": 1, + "type": "integer" + }, + "lease_id": { + "description": "Current caller-held lease UUID.", + "example": "string", + "type": "string" + }, + "session_id": { + "description": "Current coding-session UUID.", + "example": "string", + "type": "string" + } + }, + "required": [ + "lease_id", + "session_id" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskSessionLease" + } + } + }, + "description": "The renewed caller-held lease." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Task is not assigned to the authenticated user" + }, + "404": { + "description": "Task not found" + }, + "409": { + "description": "Task lease has expired; Task lease does not match the current holder" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Renew a task session lease", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/tasks/{task}/links": { + "delete": { + "operationId": "delete_api_v1_tasks__task_links", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "HTTP 204 on success." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task not found; Resource not found" + }, + "502": { + "description": "Service unavailable" + } + }, + "summary": "Remove an external link from a task", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "operationId": "post_api_v1_tasks__task_links", + "parameters": [ + { + "description": "Task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "external_scope": "string", + "object_id": "string", + "object_type": "string" + }, + "properties": { + "external_scope": { + "description": "External container ID.", + "example": "string", + "type": "string" + }, + "object_id": { + "description": "External object ID.", + "example": "string", + "type": "string" + }, + "object_type": { + "description": "External object type.", + "example": "string", + "type": "string" + } + }, + "required": [ + "external_scope", + "object_type", + "object_id" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + }, + "description": "The created external link." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task not found" + }, + "422": { + "description": "Invalid parameters" + }, + "502": { + "description": "Service unavailable" + } + }, + "summary": "Add an external link to a task", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/tasks/{task}/subtasks": { + "get": { + "description": "Returns a bounded page of the specified task's subtasks (tasks whose\n`parent` is this task), newest first. Subtasks nest exactly one level, so\nentries never have subtasks of their own. Privileged callers explicitly\nprovide the owning `team`, `user`, or `agent` and `org`.\n", + "operationId": "get_api_v1_tasks__task_subtasks", + "parameters": [ + { + "description": "Parent task ID (`tsk_...`).", + "example": "string", + "in": "path", + "name": "task", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning team (`tem_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning user (`usr_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit owning agent (`agi_...`) for privileged calls.", + "example": "string", + "in": "query", + "name": "agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit organization (`org_...`) for privileged calls; pass null when unscoped.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum subtasks to return. Capped at 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the previous page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Subtasks of the task.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "data": { + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A task representing a unit of work, optionally assignable to a user or agent.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "blocked_by_count": { + "description": "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind.", + "example": 1, + "type": "integer" + }, + "closed_at": { + "description": "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "comments_count": { + "description": "Total number of comments posted on this task.", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the task was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by_actor": { + "description": "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "created_by_agent": { + "description": "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_by_user": { + "description": "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "current_lease": { + "description": "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "nullable": true, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the coding session.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the coding session that holds the lease.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "session_name", + "harness", + "expires_at" + ], + "type": "object" + }, + "description": { + "description": "Long-form description or notes for the task. `null` if no description has been provided.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Task ID (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_blocked": { + "description": "`true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read.", + "example": true, + "type": "boolean" + }, + "links": { + "description": "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title of the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_actor": { + "description": "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "owner_agent": { + "description": "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_user": { + "description": "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level.", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "priority": { + "description": "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set.", + "example": 2, + "type": "integer" + }, + "sandbox": { + "description": "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`.", + "example": "open", + "type": "string" + }, + "subtasks_count": { + "description": "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.", + "example": 1, + "type": "integer" + }, + "tags": { + "description": "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the task was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "List a task's subtasks", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/team_memberships": { + "get": { + "description": "Returns a paginated list of team memberships across all teams accessible to\nthe authenticated caller. Use the `team`, `user`, and `agent` filters to\nnarrow results to a specific team or principal.\n\nThis endpoint requires S2S (service-to-service) authentication. Callers\nauthenticated with a user token receive a 401. Each membership includes the\nresolved `type` (`\"user\"`, `\"agent\"`, or `\"unknown\"`), display name, and\nprofile picture derived from the associated user or agent at request time.\n\nResults are returned in offset-based pages. Pass `page` and `page_size` to\nnavigate; the response includes `has_next` and `has_prev` to determine\nwhether adjacent pages exist.\n", + "operationId": "get_api_v1_team_memberships", + "parameters": [ + { + "description": "Filter results to memberships belonging to these team IDs (`tm_...`). Multiple values are combined with OR.", + "example": [ + "string" + ], + "in": "query", + "name": "team", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Filter results to memberships held by these user IDs (`usr_...`). Multiple values are combined with OR.", + "example": [ + "string" + ], + "in": "query", + "name": "user", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Filter results to memberships held by these agent IDs (`agt_...`). Multiple values are combined with OR.", + "example": [ + "string" + ], + "in": "query", + "name": "agent", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Page number to retrieve, starting at `1`. Defaults to `1`.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of memberships to return per page. Defaults to `25`.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamMembershipListResponse" + } + } + }, + "description": "Paginated list of team memberships matching the applied filters." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "summary": "List team memberships", + "tags": [ + "s2s" + ], + "x-auth": [ + "secret_key" + ] + } + }, + "/api/v1/team_memberships/{team_membership}": { + "delete": { + "description": "Removes a team membership identified directly by its membership ID. On\nsuccess, returns 204 No Content.\n\nThis endpoint is intended for server-to-server callers that already hold the\nmembership ID. To remove a member by user or agent ID instead, use the team\nmembers delete endpoint. The caller must have permission to manage the team\nthat the membership belongs to.\n", + "operationId": "delete_api_v1_team_memberships__team_membership", + "parameters": [ + { + "description": "Team membership ID (`tmb_...`) to remove. The membership must be within the caller's app scope.", + "example": "string", + "in": "path", + "name": "team_membership", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response. Returns 204 No Content on success." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Team or member not found" + } + }, + "summary": "Remove a team membership by ID", + "tags": [ + "s2s" + ], + "x-auth": [ + "secret_key" + ] + } + }, + "/api/v1/teams": { + "get": { + "description": "Returns a paginated list of teams visible to the authenticated user, ordered\nby creation time descending. Use `membership` to narrow results to teams the\ncaller has joined or teams they are eligible to join based on their ACL\nvisibility.\n\nSupports full-text search across team name and description via `search`, and\nstructured metadata filtering via `metadata`. When `app` is present, results\nare scoped to that app and the caller must hold the corresponding app scope.\n", + "operationId": "get_api_v1_teams", + "parameters": [ + { + "description": "Page number to retrieve, starting at 1. Defaults to 1.", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of teams to return per page. Defaults to 25.", + "example": 1, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Full-text search string matched against team name and description.", + "example": "string", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Structured metadata filter expression. Only teams whose metadata satisfies the expression are returned.", + "in": "query", + "name": "metadata", + "required": false, + "schema": { + "description": "A recursive boolean expression tree for filtering records by their JSON metadata field.\n\nEach node is either a group (`and`, `or`, `not`) with nested `clauses`, or a leaf\npredicate (`eq`, `contains`, `exists`) that targets a specific path inside the\nmetadata object. Leaf predicates use `path` (an array of key segments) to address\nnested values.\n\nOperator notes:\n- `eq` performs deep JSONB equality on the value at `path`.\n- `contains` checks whether the stored metadata structurally contains the given value;\n this is the only operator backed by the GIN index and is preferred for performance.\n- `exists` checks whether `path` is present in the metadata object; a key whose value\n is explicitly `null` still satisfies this predicate.\n- `and` and `or` accept two or more `clauses`; `not` accepts exactly one.\n\nThe legacy flat shape (`type: \"metadata\"`, `key`, `value`) is still accepted and is\ntreated as an `eq` predicate. Prefer the structured form for new integrations.\n", + "examples": [ + { + "clauses": [ + { + "operator": "eq", + "path": [ + "type" + ], + "value": "agent_network" + }, + { + "clauses": [ + { + "operator": "exists", + "path": [ + "collaborations", + "org_123" + ] + }, + { + "operator": "eq", + "path": [ + "customer_tier" + ], + "value": "enterprise" + } + ], + "operator": "or" + } + ], + "operator": "and" + } + ], + "properties": { + "clause": { + "description": "Single child expression node. Alternative to `clauses` when `operator` is `not`.", + "type": "object" + }, + "clauses": { + "description": "Array of child expression nodes. Required for `and` and `or` (two or more items) and `not` (exactly one item).", + "items": { + "type": "object" + }, + "type": "array" + }, + "key": { + "deprecated": true, + "description": "Deprecated. Top-level metadata key; equivalent to a single-element `path`. Use `path` instead.", + "type": "string" + }, + "operator": { + "description": "The boolean group operator (`and`, `or`, `not`) or leaf predicate operator (`eq`, `contains`, `exists`) for this node.", + "enum": [ + "and", + "or", + "eq", + "contains", + "exists", + "not" + ], + "type": "string" + }, + "path": { + "description": "Ordered key segments addressing a nested location inside the metadata object, e.g. `[\"collaborations\", \"org_123\"]`.", + "items": { + "type": "string" + }, + "type": "array" + }, + "type": { + "deprecated": true, + "description": "Deprecated. Legacy discriminator; `type: \"metadata\"` combined with `key`/`value` is treated as an `eq` predicate. Use `operator` instead.", + "type": "string" + }, + "value": { + "description": "The JSON value to compare against the node at `path`. Required for `eq` and `contains` predicates; omitted for `exists`." + } + }, + "type": "object" + } + }, + { + "description": "Filter teams by membership status. `\"joined\"` returns only teams the caller is a member of. `\"joinable\"` returns ACL-visible teams the caller has not yet joined. Omit to return all visible teams.", + "example": "string", + "in": "query", + "name": "membership", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Paginated list of teams matching the query.", + "example": { + "data": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + } + ], + "has_next": true, + "has_prev": true, + "page": 1, + "page_size": 1, + "total_entries": 1, + "total_pages": 1 + }, + "properties": { + "data": { + "description": "Array of team objects for the current page.", + "example": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + } + ], + "items": { + "description": "A team within an organization, used to group users and agents and scope resources like configs, agents, and tasks.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "acl": { + "description": "Access control list governing visibility and join permissions for this team. `null` when no ACL restrictions are applied and the team inherits default access rules.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the developer application this team belongs to (`dap_...`). `null` if the team is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "badges": { + "description": "Aggregated badge counts for the team, keyed by category. `null` when badge data is not loaded.", + "example": {}, + "type": "object" + }, + "created_at": { + "description": "When this team was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Human-readable description of the team's purpose. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Team ID (`tem_...`).", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "membership_status": { + "description": "The authenticated viewer's role on this team. One of `\"owner\"`, `\"admin\"`, or `\"member\"`. `null` if the viewer is not a member.", + "example": "member", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this team. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Display name of the team.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this team belongs to (`org_...`). `null` if the team is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this team is scoped to (`dsb_...`). `null` outside sandbox contexts.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "slug": { + "description": "URL-safe slug for the team, derived from the team name. `null` if not set.", + "example": "example-slug", + "type": "string" + }, + "updated_at": { + "description": "When this team was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "has_next": { + "description": "`true` if there is a subsequent page of results.", + "example": true, + "type": "boolean" + }, + "has_prev": { + "description": "`true` if there is a preceding page of results.", + "example": true, + "type": "boolean" + }, + "page": { + "description": "The current page number.", + "example": 1, + "type": "integer" + }, + "page_size": { + "description": "The number of results per page.", + "example": 1, + "type": "integer" + }, + "total_entries": { + "description": "Total number of teams matching the query across all pages.", + "example": 1, + "type": "integer" + }, + "total_pages": { + "description": "Total number of pages given the current `page_size`.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "data", + "page", + "page_size", + "total_entries", + "total_pages", + "has_next", + "has_prev" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Bad request - invalid metadata filter" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + } + }, + "summary": "List teams", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new team and returns the created team object. The authenticated\nuser becomes the team's owner.\n\nWhen `app` is supplied, the request is scoped to that app and the caller\nmust hold the corresponding app scope. Omit `org` unless you want the team\npinned to a specific organization. A default chat thread is provisioned for\nthe team automatically after creation.\n", + "operationId": "post_api_v1_teams", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "description": "An example description.", + "idempotency_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "string" + }, + "properties": { + "acl": { + "description": "Access control configuration for the team. Controls who can discover and join the team.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "description": { + "description": "Optional human-readable description of the team's purpose.", + "example": "An example description.", + "type": "string" + }, + "idempotency_key": { + "description": "Optional retry key. Replays in the same app, organization, and sandbox return the original team.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value pairs you can attach to the team for your own use. Values must be strings.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Display name for the team.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) to associate the team with. Omit to create the team without an org affiliation.", + "example": "string", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Team" + } + } + }, + "description": "The newly created team." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create a team", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/join_by_code": { + "post": { + "description": "Adds a principal to a team using a 12-character invite code. The invite\ncode can be supplied as either `join_code` or `invite_code`; both are\naccepted for backwards compatibility.\n\nFor user-authenticated requests, the currently authenticated user is added\nto the team. For server-to-server requests, you must supply either `agent`\n(to add an agent) or `user` (to add a specific user by ID). If the user\nis already a member of the team, the request succeeds without creating a\nduplicate membership.\n\nThis endpoint is rate-limited to 10 requests per minute per IP address to\nprevent invite-code enumeration.\n", + "operationId": "post_api_v1_teams_join_by_code", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "invite_code": "string", + "join_code": "string", + "user": "string" + }, + "properties": { + "agent": { + "description": "Agent ID (`agent_...`) to add to the team. When provided, the agent is joined instead of the authenticated user. Requires a server-to-server session.", + "example": "string", + "type": "string" + }, + "invite_code": { + "description": "12-character invite code — alias for `join_code` accepted for backwards compatibility.", + "example": "string", + "type": "string" + }, + "join_code": { + "description": "12-character invite code that identifies the team. Mutually usable with `invite_code`.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID (`user_...`) to add to the team. Required for server-to-server requests when `agent` is not supplied.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Team" + } + } + }, + "description": "The team the principal has joined." + }, + "400": { + "description": "Invalid join code format" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Invalid or expired join code" + }, + "429": { + "description": "Too many requests" + } + }, + "summary": "Join a team with an invite code", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}": { + "delete": { + "description": "Permanently deletes the team identified by `team`. This action is\nirreversible — all team memberships, settings, and associated data are\nremoved.\n\nThe caller must be the team owner or an org admin. When `app` is present,\nthe caller must also hold the corresponding app scope.\n", + "operationId": "delete_api_v1_teams__team", + "parameters": [ + { + "description": "Team ID (`team_...`) of the team to delete.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response — the team has been deleted." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Team not found" + } + }, + "summary": "Delete a team", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the full team object for the given `team` ID, including its current\nmember list and all associated threads.\n\nThe authenticated user must be a member of the team or hold a role that\ngrants visibility (org admin, app scope). When `app` is supplied, the\ncaller must hold the corresponding app scope.\n", + "operationId": "get_api_v1_teams__team", + "parameters": [ + { + "description": "Team ID (`team_...`) of the team to retrieve.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Team" + } + } + }, + "description": "The requested team, including its members and threads." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Team not found" + } + }, + "summary": "Retrieve a team", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "patch": { + "description": "Updates one or more attributes of the team identified by `team`. Only the\nfields you provide are changed; omitted fields are left as-is.\n\nTo replace the team's profile picture, supply the `profile_picture` object\nwith base64-encoded image data. The previous picture is deleted after the\nnew one is successfully uploaded. When `app` is present, the caller must hold\nthe corresponding app scope. The caller must be a team owner or org admin.\n", + "operationId": "patch_api_v1_teams__team", + "parameters": [ + { + "description": "Team ID (`team_...`) of the team to update.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "description": "An example description.", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "profile_picture": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + } + }, + "properties": { + "acl": { + "description": "New access control configuration for the team. Replaces the existing ACL.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "description": { + "description": "New human-readable description of the team's purpose.", + "example": "An example description.", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value pairs to set on the team. Replaces the existing metadata map entirely.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "New display name for the team.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "New profile picture for the team. Provide this object to upload and replace the current picture.", + "example": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "properties": { + "data": { + "description": "Base64-encoded binary image data.", + "example": "string", + "type": "string" + }, + "filename": { + "description": "Original filename of the image, used for storage metadata.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`.", + "example": "application/json", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Team" + } + } + }, + "description": "The updated team with all changes applied." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "404": { + "description": "Team not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Update a team", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/artifacts": { + "get": { + "description": "Returns all artifacts owned by the specified team. Artifacts represent\nAI-generated or user-uploaded files associated with agent sessions,\nthreads, or sandboxes — such as images, documents, and code outputs.\n\nThe authenticated user must be a member of the team. Attempting to list\nartifacts for a team the caller does not have access to returns 404\nrather than 403 to avoid leaking team existence.\n\nResults are returned in a single page without cursor pagination. Each\nartifact in the response reflects the state of its current version,\nincluding a short-lived signed `file_url` for direct download.\n", + "operationId": "get_api_v1_teams__team_artifacts", + "parameters": [ + { + "description": "Team ID (`tea_...`). The authenticated user must be a member of this team.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "All artifacts owned by the team.", + "example": { + "data": [ + { + "agent": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "current_version": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "file": "string", + "file_name": "Example Name", + "file_url": "https://example.com", + "id": "art_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + } + ] + }, + "properties": { + "data": { + "description": "Array of artifact objects belonging to the team.", + "example": [ + { + "agent": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "current_version": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "file": "string", + "file_name": "Example Name", + "file_url": "https://example.com", + "id": "art_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + } + ], + "items": { + "description": "A versioned artifact produced or managed by an agent, such as a generated file, report, or code output.", + "example": { + "agent": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "current_version": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "file": "string", + "file_name": "Example Name", + "file_url": "https://example.com", + "id": "art_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + }, + "properties": { + "agent": { + "description": "ID of the agent that produced this artifact (`agt_...`). `null` if not agent-produced.", + "example": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "content_type": { + "description": "MIME type of the current version's file, e.g. `\"text/csv\"` or `\"image/png\"`. `null` if no file is attached.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When the artifact was first created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "current_version": { + "description": "ID of the current (latest published) artifact version (`artv_...`). `null` if no version has been published.", + "example": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "description": { + "description": "Optional longer description of the artifact's contents or purpose. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "file": { + "description": "Storage file ID for the current version (`fil_...`). `null` if no file is attached.", + "example": "string", + "type": "string" + }, + "file_name": { + "description": "Original filename of the current version's file, e.g. `\"output.csv\"`. `null` if no file is attached.", + "example": "Example Name", + "type": "string" + }, + "file_url": { + "description": "Short-lived signed URL for downloading the current version's file. `null` if no file is attached.", + "example": "https://example.com", + "type": "string" + }, + "id": { + "description": "Artifact ID (`art_...`).", + "example": "art_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Image source metadata for rendering the current version's file inline. Present only when `content_type` starts with `\"image/\"`. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "description": "Human-readable name for the artifact, e.g. `\"Q2 Report\"`. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this artifact belongs to (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Identifier of the sandbox environment associated with this artifact. `null` if not sandbox-scoped.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this artifact (`tea_...`). `null` if not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread in which this artifact was created (`thr_...`). `null` if not thread-scoped.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the artifact record was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user who created this artifact (`usr_...`). `null` if not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "version": { + "description": "Current version number of the artifact. Increments each time a new version is published.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Team not found" + } + }, + "summary": "List a team's artifacts", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/custom_objects": { + "get": { + "description": "Returns a paginated list of custom objects owned by the specified team,\nfiltered to a single schema type. Results are ordered by creation time\ndescending unless `query` is provided, in which case they are ordered by\nfull-text relevance score descending.\n\nUse `limit` and `offset` for page-based pagination. Use `row_key` or\n`sort_key` to narrow results to objects matching those index values.\nFull-text search via `query` operates only against the fields configured\nas `search_fields` on the schema.\n\nThe authenticated user must be a member of the team with sufficient\naccess. Returns 404 if the team is not found, the caller lacks access,\nor `type` does not match a registered schema for the team's organization.\n", + "operationId": "get_api_v1_teams__team_custom_objects", + "parameters": [ + { + "description": "Team ID (`team_...`). Scopes results to objects owned by this team.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Schema type identifier (`lookup_key`) that filters results to objects of this schema.", + "example": "string", + "in": "query", + "name": "type", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of objects to return per page.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Number of objects to skip before returning results. Use with `limit` for page-based pagination.", + "example": 1, + "in": "query", + "name": "offset", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Filter results to objects whose `row_key` exactly matches this value.", + "example": "string", + "in": "query", + "name": "row_key", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter results to objects whose `sort_key` exactly matches this value.", + "example": "string", + "in": "query", + "name": "sort_key", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Full-text search string matched against the schema's configured `search_fields`. When provided, results are ordered by relevance score descending instead of creation time descending.", + "example": "string", + "in": "query", + "name": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Paginated list of custom objects owned by the team.", + "example": { + "data": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "created_at": "2024-01-01T00:00:00Z", + "fields": { + "key": "value" + }, + "id": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "row_key": "string", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "schema_type": "contact", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + } + ], + "meta": {} + }, + "properties": { + "data": { + "description": "Array of custom object records for the current page.", + "example": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "created_at": "2024-01-01T00:00:00Z", + "fields": { + "key": "value" + }, + "id": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "row_key": "string", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "schema_type": "contact", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + } + ], + "items": { + "description": "A custom object belonging to an organization. Custom objects store arbitrary structured data defined by a schema type and are scoped to an org, team, or user.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "created_at": "2024-01-01T00:00:00Z", + "fields": { + "key": "value" + }, + "id": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "row_key": "string", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "schema_type": "contact", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + }, + "properties": { + "acl": { + "description": "Access control list governing read and write access to this custom object. Only returned to resource owners and privileged or organization-admin viewers; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "created_at": { + "description": "When the custom object was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "fields": { + "description": "Map of field names to their current values as defined by the object's schema type.", + "example": { + "key": "value" + }, + "type": "object" + }, + "id": { + "description": "Unique identifier for the custom object (`cobj_...`).", + "example": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org": { + "description": "ID of the organization this object belongs to (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "row_key": { + "description": "An optional stable key used to identify this object by a caller-controlled string rather than its generated ID. `null` if not set.", + "example": "string", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this object is scoped to (`dsb_...`). `null` for production objects.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "schema_type": { + "description": "The lookup key of the schema type that defines this object's field structure. `null` if the schema type has not been set.", + "example": "contact", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this object (`tem_...`). `null` if the object is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the custom object was last modified (ISO 8601). `null` if the object has never been updated after creation.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this object (`usr_...`). `null` if the object is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "version": { + "description": "Optimistic concurrency version of the object. Increments with each successful update; pass this value in write operations to detect conflicting changes.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "meta": { + "description": "Pagination metadata for the response.", + "example": {}, + "type": "object" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Team not found or schema type not found" + } + }, + "summary": "List a team's custom objects", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new custom object owned by the specified team. The object is\ninstantiated against the schema identified by `type` (the schema's\n`lookup_key`). All field values are validated against that schema's\nfield definitions before the object is persisted.\n\nThe authenticated user must be a member of the team with sufficient\naccess. If the team is not found or the caller lacks access, the endpoint\nreturns 404. If `type` does not match a registered schema for the team's\norganization, the endpoint also returns 404.\n", + "operationId": "post_api_v1_teams__team_custom_objects", + "parameters": [ + { + "description": "Team ID (`team_...`). The team that will own the created object.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "fields": {}, + "type": "string" + }, + "properties": { + "fields": { + "description": "Map of field values to set on the new object. Keys and value types must conform to the schema identified by `type`.", + "example": {}, + "type": "object" + }, + "type": { + "description": "Schema type identifier (`lookup_key`) that defines the object's fields and validation rules.", + "example": "string", + "type": "string" + } + }, + "required": [ + "type", + "fields" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomObject" + } + } + }, + "description": "The newly created custom object." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Team not found or schema type not found" + }, + "422": { + "description": "Validation error" + } + }, + "summary": "Create a team custom object", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/invite": { + "post": { + "description": "Generates a new invite code for the specified team. The authenticated user\nmust be a member of the team with the `owner` or `admin` role.\n\nThe returned code is a short alphanumeric string that other users can\npresent to join the team. Each call produces a new code; previously issued\ncodes are not invalidated by this request.\n", + "operationId": "post_api_v1_teams__team_invite", + "parameters": [ + { + "description": "Team ID (`tm_...`) identifying the team for which to generate the invite code.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamInvite" + } + } + }, + "description": "The newly created team invite containing the join code." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Team not found" + } + }, + "summary": "Create a team invite", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/invites": { + "post": { + "description": "Generates a new invite code for the specified team using server-to-server\nauthentication. Unlike the user-facing create endpoint, this variant does not\nrequire the caller to be a team member — it is intended for privileged\nback-end services acting on behalf of your platform.\n\nThe returned code is a short alphanumeric string that users can present to\njoin the team. Each call produces a new code; previously issued codes are\nnot invalidated by this request.\n", + "operationId": "post_api_v1_teams__team_invites", + "parameters": [ + { + "description": "Team ID (`tm_...`) identifying the team for which to generate the invite code.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "The newly created team invite containing the join code.", + "example": { + "code": "string" + }, + "properties": { + "code": { + "description": "Six-character alphanumeric join code. Present this value to the join-team endpoint to add a user to the team.", + "example": "string", + "type": "string" + } + }, + "required": [ + "code" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Team not found" + } + }, + "summary": "Create a team invite (server-to-server)", + "tags": [ + "s2s" + ], + "x-auth": [ + "secret_key" + ] + } + }, + "/api/v1/teams/{team}/join": { + "post": { + "description": "Adds a principal to a team that is visible to the authenticated user.\n\nBy default, the currently authenticated user joins the team. Provide `agent`\nto add an agent to the team instead — the caller must already be a member of\nthe team to do so. Provide `user` (by ID) or `email` to add another user from\nyour organization — the caller must be a team owner, team admin, or org admin.\nOnly one of `agent`, `user`, or `email` may be supplied per request.\n\nIf the target principal is already a member of the team, the request succeeds\nwithout creating a duplicate membership. Server-to-server callers are not\npermitted to use this endpoint; use the invite-code endpoint instead.\n", + "operationId": "post_api_v1_teams__team_join", + "parameters": [ + { + "description": "Team ID (`team_...`) to join.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "email": "user@example.com", + "user": "string" + }, + "properties": { + "agent": { + "description": "Agent ID (`agent_...`) to add to the team. The caller must already be a member of the team.", + "example": "string", + "type": "string" + }, + "email": { + "description": "Email address of a member of the caller's organization to add to the team. Requires team-owner, team-admin, or org-admin role.", + "example": "user@example.com", + "type": "string" + }, + "user": { + "description": "User ID (`user_...`) of a member of the caller's organization to add to the team. Requires team-owner, team-admin, or org-admin role.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Empty response — the principal is now a member of the team." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + } + }, + "summary": "Join a team", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/leave": { + "delete": { + "description": "Removes a principal from a team. By default, the authenticated user removes\nthemselves from the team. Provide `agent` to remove an agent instead — the\ncaller must be a member of the team to do so.\n\nTeam owners cannot leave their own team. To transfer ownership first, use\nthe update-membership endpoint, then call this endpoint.\n\nFor server-to-server requests, `user` is required to identify which user\nshould be removed.\n", + "operationId": "delete_api_v1_teams__team_leave", + "parameters": [ + { + "description": "Team ID (`team_...`) to leave.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response — the principal has been removed from the team." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not a member of this team" + }, + "422": { + "description": "Failed to leave team" + } + }, + "summary": "Leave a team", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/members": { + "delete": { + "description": "Removes a user, agent, or all members of an organization from the specified\nteam. Provide exactly one of `user`, `agent`, or `org` — supplying more than\none or none returns a 400 error. On success, returns 204 No Content.\n\nWhen `org` is provided, every user and agent membership belonging to that org\nis removed in a single call. The caller must be a member of the team's owning\norg to perform an org-scoped removal. You cannot target the team's owning org\nitself with this parameter.\n\nThe caller must have permission to manage the team. When `app` is present, the\nrequest is scoped to that app and requires a valid app-scoped token.\n", + "operationId": "delete_api_v1_teams__team_members", + "parameters": [ + { + "description": "Team ID (`team_...`). The team to remove the member from.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response. Returns 204 No Content on success." + }, + "400": { + "description": "Provide exactly one of user, agent, or org" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Team or member not found" + } + }, + "summary": "Remove a member or org from a team", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns all members of the specified team, including both users and agents.\nMembers are returned in a single non-paginated array ordered by join time.\n\nBearer-authenticated users must be a member of the team to retrieve its\nmember list. Developer and server-to-server callers can retrieve members for\nany team visible to their app scope. When `app` is provided, the request is\nscoped to that app and requires a valid app-scoped token.\n", + "operationId": "get_api_v1_teams__team_members", + "parameters": [ + { + "description": "Team ID (`team_...`). The team whose members you want to list.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Array of team memberships for the specified team.", + "example": { + "data": [ + { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "created_at": "2024-01-01T00:00:00Z", + "id": "tmb_0aBcDeFgHiJkLmNoPqRsTu", + "joined_at": "2024-01-01T00:00:00Z", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "role": "member", + "team": {}, + "type": "user", + "updated_at": "2024-01-01T00:00:00Z", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + } + ] + }, + "properties": { + "data": { + "description": "Array of team membership objects, including both user and agent members.", + "example": [ + { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "created_at": "2024-01-01T00:00:00Z", + "id": "tmb_0aBcDeFgHiJkLmNoPqRsTu", + "joined_at": "2024-01-01T00:00:00Z", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "role": "member", + "team": {}, + "type": "user", + "updated_at": "2024-01-01T00:00:00Z", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + } + ], + "items": { + "description": "A record representing a user's or agent's membership in a team, including their resolved identity details and role.", + "example": { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "created_at": "2024-01-01T00:00:00Z", + "id": "tmb_0aBcDeFgHiJkLmNoPqRsTu", + "joined_at": "2024-01-01T00:00:00Z", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "role": "member", + "team": {}, + "type": "user", + "updated_at": "2024-01-01T00:00:00Z", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + }, + "properties": { + "agent": { + "description": "The agent associated with this membership, as an expanded agent object. `null` when the member is a user, the type is unknown, or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints.", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "solution": { + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "created_at": { + "description": "When this membership record was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Team membership ID (`tmb_...`).", + "example": "tmb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "joined_at": { + "description": "When the principal joined the team (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this membership record. `null` if no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Display name of the member, derived from the associated user or agent. `null` if the principal is unknown.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture of the member, derived from the associated user or agent. `null` if not set or principal is unknown.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "role": { + "description": "The member's role within the team. One of `\"owner\"`, `\"admin\"`, or `\"member\"`.", + "example": "member", + "type": "string" + }, + "team": { + "description": "The team this membership belongs to, as an expanded team object. `null` when the team association is not preloaded.", + "example": {}, + "type": "object" + }, + "type": { + "description": "Resolved principal type. One of `\"user\"`, `\"agent\"`, or `\"unknown\"` when the principal cannot be determined.", + "example": "user", + "type": "string" + }, + "updated_at": { + "description": "When this membership record was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "The user associated with this membership, as an expanded user object. `null` when the member is an agent, the type is unknown, or the association is not preloaded.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Team not found" + } + }, + "summary": "List members of a team", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Adds a user or agent as a member of the specified team and returns the new\nmembership with HTTP 201. Provide exactly one of `user` or `agent` — supplying\nboth or neither returns a 400 error.\n\nThe caller must have permission to manage the team. When an `app` is provided,\nthe request is scoped to that app and the caller must hold a valid app-scoped\ntoken. The default role is `\"member\"` when `role` is omitted.\n", + "operationId": "post_api_v1_teams__team_members", + "parameters": [ + { + "description": "Team ID (`team_...`). The team to add the member to.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "role": "string", + "user": "string" + }, + "properties": { + "agent": { + "description": "Agent ID (`agt_...`) to add as a member. Provide exactly one of `user` or `agent`.", + "example": "string", + "type": "string" + }, + "role": { + "description": "Role to assign. One of `\"owner\"`, `\"admin\"`, or `\"member\"`. Defaults to `\"member\"` when omitted.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID (`usr_...`) to add as a member. Provide exactly one of `user` or `agent`.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamMembership" + } + } + }, + "description": "The newly created team membership." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Team or member not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Add a member to a team", + "tags": [ + "s2s" + ], + "x-auth": [ + "secret_key" + ] + } + }, + "/api/v1/teams/{team}/members/{user}": { + "patch": { + "description": "Changes the role of an existing user member on the specified team. Returns the\nupdated membership on success.\n\nOnly user memberships are supported by this endpoint. Attempting to update an\nagent membership returns 404. To change an agent's role, remove the existing\nmembership and re-add the agent with the desired role.\n\nThe caller must have permission to modify the team. You cannot change a member's\nrole across organization boundaries. Demoting the last owner of a team returns\n409. An invalid `role` value returns 422. When `app` is provided, the request\nis scoped to that app and requires a valid app-scoped token.\n", + "operationId": "patch_api_v1_teams__team_members__user", + "parameters": [ + { + "description": "Team ID (`team_...`). The team whose member role you want to update.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) of the existing member whose role should be changed.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "role": "string" + }, + "properties": { + "role": { + "description": "New role to assign. One of `\"owner\"`, `\"admin\"`, or `\"member\"`.", + "example": "string", + "type": "string" + } + }, + "required": [ + "role" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamMembership" + } + } + }, + "description": "The updated team membership reflecting the new role." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden — caller lacks permission to modify this team" + }, + "404": { + "description": "Team or member not found" + }, + "409": { + "description": "Conflict — cannot demote the last owner" + }, + "422": { + "description": "Validation failed (e.g. invalid role)" + } + }, + "summary": "Update a team member's role", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/task_assignees": { + "get": { + "description": "Returns the list of principals — users and agents — that can be assigned\nto tasks within the team. Results include both human members and AI agents\nand are sorted alphabetically by display name.\n\nThis endpoint is only available for team-scoped contexts. Calling it with a\nuser-scoped owner returns a 400 error. The authenticated user must be a\nmember of the team or hold org-admin access. App-scoped developer and\nserver-to-server callers may list assignees for teams in their app so they\ncan select the explicit user or agent actor required by privileged task\nmutations.\n", + "operationId": "get_api_v1_teams__team_task_assignees", + "parameters": [ + { + "description": "Team ID (`tem_...`).", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Explicit organization (`org_...`) for developer and server-to-server calls. Pass null for a team outside an organization.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Assignable users and agents for the team.", + "example": { + "data": [ + { + "actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "id": "string", + "type": "user" + } + ] + }, + "properties": { + "data": { + "description": "Users and agents that can be assigned to tasks owned by the team.", + "example": [ + { + "actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "id": "string", + "type": "user" + } + ], + "items": { + "description": "A user or agent that can be assigned to a team-owned task.", + "example": { + "actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "id": "string", + "type": "user" + }, + "properties": { + "actor": { + "description": "Resolved display details for the assignable principal.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "id": { + "description": "User (`usr_...`) or agent (`agi_...`) ID.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Principal type: `user` or `agent`.", + "enum": [ + "user", + "agent" + ], + "example": "user", + "type": "string" + } + }, + "required": [ + "id", + "type", + "actor" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task owner not found" + }, + "422": { + "description": "Invalid explicit owner or organization context" + } + }, + "summary": "List task assignees for a team", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/tasks": { + "get": { + "description": "Returns tasks owned by the specified user or team. You can narrow results using the\noptional filters below. By default results are returned in reverse chronological\norder (most recently created first); use `sort` and `order` to sort by due date or\npriority instead.\n\nUser-authenticated callers may list their personal tasks or tasks for teams they\nhave joined. Privileged callers provide the owner in the route; the owner's\norganization is implied by that principal. An explicit `org` is optional and,\nwhen set, must match the owner's organization.\n", + "operationId": "get_api_v1_teams__team_tasks", + "parameters": [ + { + "description": "Team ID (`tem_...`). Only tasks belonging to this team are returned.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) for user-scoped tasks.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Optional organization (`org_...`) for developer and server-to-server calls. When omitted, the org is taken from the owner principal (team, user, or agent). When set, it must match that principal's org; pass null for an owner outside an organization.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter tasks by status. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`. Omit to return tasks in all statuses.", + "example": "string", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter tasks assigned to a specific user. Provide the user's public ID (`usr_...`).", + "example": "string", + "in": "query", + "name": "owner_user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter tasks assigned to a specific agent. Provide the agent's public ID (`agi_...`).", + "example": "string", + "in": "query", + "name": "owner_agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter tasks by priority, from 0 (highest) to 4 (lowest).", + "example": 1, + "in": "query", + "name": "priority", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Return only tasks carrying this tag (matched against the canonical lowercase form).", + "example": "string", + "in": "query", + "name": "tag", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return only subtasks of the given task (`tsk_...`), or pass `none` to return only top-level tasks.", + "example": "string", + "in": "query", + "name": "parent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Restrict results to tasks whose name or description contains this string.", + "example": "string", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Sort key. One of `\"created\"` (default — most recently created first), `\"due_date\"` (soonest due first; tasks without a due date always sort last), or `\"priority\"` (most urgent first). Ties break by most recently created.", + "example": "string", + "in": "query", + "name": "sort", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Sort direction, `\"asc\"` or `\"desc\"`. Defaults to `\"desc\"` for `created` and `\"asc\"` for `due_date` and `priority`.", + "example": "string", + "in": "query", + "name": "order", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return only tasks with a due date strictly before this ISO 8601 datetime (`2026-08-01T00:00:00Z`) or date (`2026-08-01`, meaning midnight UTC). Tasks without a due date are excluded.", + "example": "string", + "in": "query", + "name": "due_before", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return only tasks with a due date strictly after this ISO 8601 datetime or date. Tasks without a due date are excluded.", + "example": "string", + "in": "query", + "name": "due_after", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "When `true`, return only overdue tasks: a due date before the current UTC day and a status other than `\"done\"`. A task due today is not overdue.", + "example": true, + "in": "query", + "name": "overdue", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "When true, return only open tasks with no unfinished blockers and no active session lease. This is a projection snapshot; claim a lease before starting work.", + "example": true, + "in": "query", + "name": "ready", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Maximum number of tasks to return. Capped at 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the previous page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Filtered list of tasks for the owner.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "data": { + "description": "Array of task objects matching the requested filters.", + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A task representing a unit of work, optionally assignable to a user or agent.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "blocked_by_count": { + "description": "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind.", + "example": 1, + "type": "integer" + }, + "closed_at": { + "description": "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "comments_count": { + "description": "Total number of comments posted on this task.", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the task was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by_actor": { + "description": "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "created_by_agent": { + "description": "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_by_user": { + "description": "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "current_lease": { + "description": "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "nullable": true, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the coding session.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the coding session that holds the lease.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "session_name", + "harness", + "expires_at" + ], + "type": "object" + }, + "description": { + "description": "Long-form description or notes for the task. `null` if no description has been provided.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Task ID (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_blocked": { + "description": "`true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read.", + "example": true, + "type": "boolean" + }, + "links": { + "description": "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title of the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_actor": { + "description": "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "owner_agent": { + "description": "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_user": { + "description": "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level.", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "priority": { + "description": "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set.", + "example": 2, + "type": "integer" + }, + "sandbox": { + "description": "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`.", + "example": "open", + "type": "string" + }, + "subtasks_count": { + "description": "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.", + "example": 1, + "type": "integer" + }, + "tags": { + "description": "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the task was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task owner not found" + }, + "422": { + "description": "Invalid explicit owner or organization context" + } + }, + "summary": "List an owner's tasks", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new task owned by the specified user or team and returns the full\ntask object. User-authenticated calls are attributed to the authenticated\nuser or agent. App-scoped developer and server-to-server callers must provide\nthe task's explicit `org` scope and an explicit `user` or `agent` actor for\nteam tasks; a user-owned task reuses the user in the route unless an explicit\nagent is supplied. Every referenced principal is validated against the app,\nowner, and team membership before creation.\n", + "operationId": "post_api_v1_teams__team_tasks", + "parameters": [ + { + "description": "Team ID (`tem_...`). The task will be owned by this team.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "org": "string", + "task": { + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "owner_agent": "string", + "owner_user": "string", + "parent": "tsk_01j3k5m7n9p2r4s6t8v0w1x2", + "priority": 2, + "status": "open", + "tags": [ + "backend", + "q3-launch" + ], + "thread": "thr_01j3k5m7n9p2r4s6t8v0w1x2" + }, + "user": "string" + }, + "properties": { + "agent": { + "description": "Explicit acting agent (`agi_...`) for a developer or server-to-server call. Mutually exclusive with an acting `user`; the agent must belong to the task owner.", + "example": "string", + "type": "string" + }, + "org": { + "description": "Explicit organization (`org_...`) for developer and server-to-server calls. Pass null when the owner is not organization-scoped. The value must match the selected user or team.", + "example": "string", + "type": "string" + }, + "task": { + "description": "Attributes for the task to create. `name` is required; all other fields are optional.", + "example": { + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "owner_agent": "string", + "owner_user": "string", + "parent": "tsk_01j3k5m7n9p2r4s6t8v0w1x2", + "priority": 2, + "status": "open", + "tags": [ + "backend", + "q3-launch" + ], + "thread": "thr_01j3k5m7n9p2r4s6t8v0w1x2" + }, + "properties": { + "description": { + "description": "Optional long-form description or notes for the task. Supports plain text.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). Omit to create the task without a due date.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "links": { + "description": "Arbitrary key-value map of named URLs or references associated with the task (e.g. external ticket links).", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map for storing application-specific data alongside the task. Omit to create the task with no metadata.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title for the task.", + "example": "Example Name", + "type": "string" + }, + "owner_agent": { + "description": "ID of the agent to assign as owner (`agi_...`). Mutually exclusive with `owner_user`; omit to leave the task unassigned.", + "example": "string", + "type": "string" + }, + "owner_user": { + "description": "ID of the user to assign as owner (`usr_...`). Mutually exclusive with `owner_agent`; omit to leave the task unassigned.", + "example": "string", + "type": "string" + }, + "parent": { + "description": "Create this task as a subtask of an existing top-level task (`tsk_...`). Subtasks nest exactly one level.", + "example": "tsk_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "priority": { + "description": "Priority level from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when omitted.", + "example": 2, + "type": "integer" + }, + "status": { + "description": "Initial status for the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`. Defaults to `\"open\"` when omitted.", + "example": "open", + "type": "string" + }, + "tags": { + "description": "Labels for grouping and filtering (max 20, each up to 40 characters). Stored canonically: lowercase, trimmed, de-duplicated.", + "example": [ + "backend", + "q3-launch" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "thread": { + "description": "Bind the task to a thread (`thr_...`) owned by the same team or user as the task. A bound task appears in that thread's task scope, exactly like a task filed from inside the conversation. Omit for a task not tied to a conversation.", + "example": "thr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "user": { + "description": "User ID (`usr_...`). On a user route this is the task owner and creator; on a team route it is the explicit acting user for a developer or server-to-server call.", + "example": "string", + "type": "string" + } + }, + "required": [ + "task" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Task" + } + } + }, + "description": "The newly created task." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task owner not found" + }, + "422": { + "description": "Validation error" + } + }, + "summary": "Create a task for an owner", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/tasks/blocker_cycles": { + "get": { + "description": "Runs an on-demand diagnostic over unfinished tasks owned by the specified\nteam or user and returns a forward cursor-paginated page of complete cyclic\nblocker components. Detection is bounded to owners with at most 100\nunfinished tasks. This endpoint is read-only: cycles do not prevent task\nupdates, lease acquisition, or completion.\n", + "operationId": "get_api_v1_teams__team_tasks_blocker_cycles", + "parameters": [ + { + "description": "Team ID (`tem_...`) owning the tasks.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) owning the tasks.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Optional organization context for privileged callers.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum cycle components to return. Defaults to 50; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the preceding page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "On-demand task blocker cycle diagnostics.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "tasks": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ] + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "data": { + "example": [ + { + "tasks": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ] + } + ], + "items": { + "description": "A strongly connected component of unfinished task blocker edges.", + "example": { + "tasks": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ] + }, + "properties": { + "tasks": { + "description": "Every unfinished task in this cyclic blocker component.", + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A task representing a unit of work, optionally assignable to a user or agent.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "blocked_by_count": { + "description": "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind.", + "example": 1, + "type": "integer" + }, + "closed_at": { + "description": "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "comments_count": { + "description": "Total number of comments posted on this task.", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the task was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by_actor": { + "description": "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "created_by_agent": { + "description": "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_by_user": { + "description": "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "current_lease": { + "description": "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "nullable": true, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the coding session.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the coding session that holds the lease.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "session_name", + "harness", + "expires_at" + ], + "type": "object" + }, + "description": { + "description": "Long-form description or notes for the task. `null` if no description has been provided.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Task ID (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_blocked": { + "description": "`true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read.", + "example": true, + "type": "boolean" + }, + "links": { + "description": "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title of the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_actor": { + "description": "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "owner_agent": { + "description": "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_user": { + "description": "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level.", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "priority": { + "description": "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set.", + "example": 2, + "type": "integer" + }, + "sandbox": { + "description": "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`.", + "example": "open", + "type": "string" + }, + "subtasks_count": { + "description": "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.", + "example": 1, + "type": "integer" + }, + "tags": { + "description": "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the task was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "tasks" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task owner not found" + }, + "422": { + "description": "Invalid owner context or diagnostic limit" + } + }, + "summary": "List task blocker cycles", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/tasks/metrics": { + "get": { + "description": "Returns task activity metrics scoped to one team (the Network in ArchAgents).\n`open` counts currently open or in-progress team tasks, `created` counts\ntasks inserted in the UTC-day window, and `completed` counts tasks whose\n`closed_at` falls in that window while still in a closed status. Hard-deleted\ntasks are absent from the projection and therefore omitted. The daily series\nis zero-filled across the requested window and includes reconstructed\nend-of-day `open` stock (from remaining projection rows' inserted_at/closed_at).\n\nAny authenticated team member may read this count-only Network summary.\nRequests from callers without team access return 404 so team existence is\nnot disclosed.\n", + "operationId": "get_api_v1_teams__team_tasks_metrics", + "parameters": [ + { + "description": "Team ID (`tem_...`) whose task metrics should be returned.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "UTC-day window. One of 7, 30, 90, or 365; defaults to 30.", + "example": 1, + "in": "query", + "name": "days", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Network-scoped task activity metrics.", + "example": { + "completed": 1, + "created": 1, + "days": 1, + "end_at": "2024-01-01T00:00:00Z", + "open": 1, + "series": [ + {} + ], + "start_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "completed": { + "example": 1, + "type": "integer" + }, + "created": { + "example": 1, + "type": "integer" + }, + "days": { + "example": 1, + "type": "integer" + }, + "end_at": { + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "open": { + "example": 1, + "type": "integer" + }, + "series": { + "description": "Zero-filled UTC-day buckets with `date`, end-of-day `open`, `created`, and `completed`.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "start_at": { + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "days", + "start_at", + "end_at", + "open", + "created", + "completed", + "series" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Team not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Get task activity metrics for a team", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/tasks/ready": { + "get": { + "description": "Returns open tasks with no unfinished blockers and no active session lease.\nReadiness is calculated by the server from the current task projection. It is\na snapshot, not a reservation; claim a task lease before starting work.\n\nPass `explain=true` to include every open task with a stable readiness reason.\n", + "operationId": "get_api_v1_teams__team_tasks_ready", + "parameters": [ + { + "description": "Team ID (`tem_...`) owning the tasks.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) owning the tasks.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Optional organization context for privileged callers.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Include blocked and actively leased open tasks with exclusion reasons.", + "example": true, + "in": "query", + "name": "explain", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Only include tasks assigned to the authenticated user.", + "example": true, + "in": "query", + "name": "assigned_to_me", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Maximum number of readiness entries to return. Capped at 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the previous page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Cursor-paginated readiness results for the owner.", + "example": { + "after_cursor": "string", + "authoritative": true, + "before_cursor": "string", + "data": [ + { + "readiness": "ready", + "reason": "open_blockers", + "task": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "authoritative": { + "description": "Always false because projections can lag writes and a later claim can race this read.", + "example": true, + "type": "boolean" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "data": { + "example": [ + { + "readiness": "ready", + "reason": "open_blockers", + "task": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + } + ], + "items": { + "description": "A task plus the server-calculated reason it is or is not ready.", + "example": { + "readiness": "ready", + "reason": "open_blockers", + "task": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + }, + "properties": { + "readiness": { + "description": "One of `ready`, `blocked`, or `leased`.", + "enum": [ + "ready", + "blocked", + "leased" + ], + "example": "ready", + "type": "string" + }, + "reason": { + "description": "Stable exclusion reason: `open_blockers` or `active_lease`; omitted when ready.", + "enum": [ + "open_blockers", + "active_lease" + ], + "example": "open_blockers", + "nullable": true, + "type": "string" + }, + "task": { + "description": "The task evaluated for readiness.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "blocked_by_count": { + "description": "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind.", + "example": 1, + "type": "integer" + }, + "closed_at": { + "description": "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "comments_count": { + "description": "Total number of comments posted on this task.", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the task was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by_actor": { + "description": "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "created_by_agent": { + "description": "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_by_user": { + "description": "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "current_lease": { + "description": "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "nullable": true, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the coding session.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the coding session that holds the lease.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "session_name", + "harness", + "expires_at" + ], + "type": "object" + }, + "description": { + "description": "Long-form description or notes for the task. `null` if no description has been provided.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Task ID (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_blocked": { + "description": "`true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read.", + "example": true, + "type": "boolean" + }, + "links": { + "description": "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title of the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_actor": { + "description": "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "owner_agent": { + "description": "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_user": { + "description": "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level.", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "priority": { + "description": "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set.", + "example": 2, + "type": "integer" + }, + "sandbox": { + "description": "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`.", + "example": "open", + "type": "string" + }, + "subtasks_count": { + "description": "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.", + "example": 1, + "type": "integer" + }, + "tags": { + "description": "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the task was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status" + ], + "type": "object" + } + }, + "required": [ + "task", + "readiness" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "authoritative", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task owner not found" + }, + "422": { + "description": "Invalid owner context or pagination cursor" + } + }, + "summary": "List an owner's ready tasks", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/tasks/search": { + "get": { + "description": "Performs a full-text search over tasks owned by the specified user or team and returns\nmatching results. Combine `q` with the optional filters to narrow the result set\nfurther. When no query is provided, the endpoint behaves like a filtered list.\n\nThe `query` field in the response echoes the effective search query.\nUser-authenticated callers may search their personal tasks or tasks for teams\nthey have joined. Privileged callers provide the owner in the route; the owner's\norganization is implied by that principal. An explicit `org` is optional and,\nwhen set, must match the owner's organization.\n", + "operationId": "get_api_v1_teams__team_tasks_search", + "parameters": [ + { + "description": "Team ID (`tem_...`). Only tasks belonging to this team are searched.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) whose tasks are searched.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Optional organization (`org_...`) for developer and server-to-server calls. When omitted, the org is taken from the owner principal (team, user, or agent). When set, it must match that principal's org; pass null for an owner outside an organization.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Full-text search query matched against task names and descriptions. Takes precedence over `query` when both are provided.", + "example": "string", + "in": "query", + "name": "q", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Alias for `q`. Use `q` when possible; this parameter exists for compatibility.", + "example": "string", + "in": "query", + "name": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter results by status. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`. Omit to include all statuses.", + "example": "string", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Restrict results to tasks assigned to the user with this public ID (`usr_...`).", + "example": "string", + "in": "query", + "name": "owner_user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Restrict results to tasks assigned to the agent with this public ID (`agi_...`).", + "example": "string", + "in": "query", + "name": "owner_agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter results by priority, from 0 (highest) to 4 (lowest).", + "example": 1, + "in": "query", + "name": "priority", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Return only tasks carrying this tag (matched against the canonical lowercase form).", + "example": "string", + "in": "query", + "name": "tag", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return only subtasks of the given task (`tsk_...`), or pass `none` to return only top-level tasks.", + "example": "string", + "in": "query", + "name": "parent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of tasks to return. Capped at 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the previous page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Search results for the owner's tasks.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "has_more": true, + "query": "string" + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "data": { + "description": "Array of task objects matching the query and filters.", + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A task representing a unit of work, optionally assignable to a user or agent.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "blocked_by_count": { + "description": "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind.", + "example": 1, + "type": "integer" + }, + "closed_at": { + "description": "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "comments_count": { + "description": "Total number of comments posted on this task.", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the task was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by_actor": { + "description": "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "created_by_agent": { + "description": "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_by_user": { + "description": "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "current_lease": { + "description": "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "nullable": true, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the coding session.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the coding session that holds the lease.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "session_name", + "harness", + "expires_at" + ], + "type": "object" + }, + "description": { + "description": "Long-form description or notes for the task. `null` if no description has been provided.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Task ID (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_blocked": { + "description": "`true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read.", + "example": true, + "type": "boolean" + }, + "links": { + "description": "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title of the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_actor": { + "description": "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "owner_agent": { + "description": "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_user": { + "description": "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level.", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "priority": { + "description": "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set.", + "example": 2, + "type": "integer" + }, + "sandbox": { + "description": "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`.", + "example": "open", + "type": "string" + }, + "subtasks_count": { + "description": "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.", + "example": 1, + "type": "integer" + }, + "tags": { + "description": "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the task was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "example": true, + "type": "boolean" + }, + "query": { + "example": "string", + "type": "string" + } + }, + "required": [ + "data", + "has_more", + "query" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task owner not found" + }, + "422": { + "description": "Invalid explicit owner or organization context" + } + }, + "summary": "Search an owner's tasks", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/threads": { + "get": { + "description": "Returns all threads owned by the specified team that the authenticated caller\nhas permission to view. The caller must have access to the team; requests\nwithout team access are rejected with 404.\n\nThreads are returned in a single `data` array, ordered with the team's\ndefault thread first, then by most recent activity (newest first). Each\nthread carries a `last_activity` timestamp — the most recent message's\ncreation time, falling back to the thread's own creation time. Use the\nteam-scoped thread endpoints to create, update, or delete individual\nthreads.\n", + "operationId": "get_api_v1_teams__team_threads", + "parameters": [ + { + "description": "Team ID (`tem_...`) whose threads should be listed.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Optional: only return threads tagged with at least one of these tags (OR-match). Repeated query params, e.g. `?tags[]=blocked&tags[]=needs-review`.", + "example": [ + "string" + ], + "in": "query", + "name": "tags", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Response envelope containing the team's threads.", + "example": { + "data": [ + { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + } + ] + }, + "properties": { + "data": { + "description": "Array of thread objects belonging to the team.", + "example": [ + { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + } + ], + "items": { + "description": "A chat thread, representing a conversation channel that can be owned by a user, team, or agent and may contain messages, participants, and AI agent activity.", + "example": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + }, + "properties": { + "agent_user": { + "description": "ID of the agent that owns this thread (`agt_...`). `null` for user-owned or team-owned threads.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the thread was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "creator": { + "description": "User who created this thread. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if the creator is unknown.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "oneOf": [ + { + "type": "string" + }, + { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + }, + "description": { + "description": "Optional description or purpose statement for the thread. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Thread ID (`thr_...`).", + "example": "string", + "type": "string" + }, + "is_channel": { + "description": "Whether this thread operates as a channel — a multi-member broadcast-style conversation.", + "example": true, + "type": "boolean" + }, + "is_default": { + "description": "Whether this is the default thread for its owner. Each user or team has at most one default thread.", + "example": true, + "type": "boolean" + }, + "is_transient": { + "description": "Whether this thread is ephemeral and may be deleted automatically after a period of inactivity or when its TTL expires.", + "example": true, + "type": "boolean" + }, + "is_unlisted": { + "description": "Whether this thread is hidden from public discovery. Unlisted threads are accessible only to direct participants.", + "example": true, + "type": "boolean" + }, + "key": { + "description": "Application-defined stable key that uniquely identifies the thread within its scope. Useful for idempotent creation. `null` if not set.", + "example": "string", + "type": "string" + }, + "kind": { + "description": "Thread subtype: `\"standard\"` for ordinary threads, `\"slack_mirror\"` for the membership-strict mirror of a Slack channel, `\"slashwork_mirror\"` for the membership-strict mirror of a Slashwork group. Read-only — derived server-side at creation, never accepted from params.", + "example": "string", + "type": "string" + }, + "last_activity": { + "description": "When the most recent message was posted in this thread, falling back to the thread's creation time if it has no messages. Always populated on thread list endpoints (which order by it, after default threads); `null` on endpoints that don't compute activity enrichment.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "last_message_preview": { + "description": "Single-line snippet of the most recent message's text content (first non-empty line, truncated to 140 characters). Populated on thread list endpoints alongside `last_activity`; `null` when the thread has no messages, the latest message has no text content (e.g. attachment-only), or the endpoint doesn't compute activity enrichment.", + "example": "Sounds good — I'll ship the fix tomorrow.", + "type": "string" + }, + "last_message_sender": { + "description": "Display name of the sender of the most recent message — the same message `last_message_preview` snippets. Populated on thread list endpoints; `null` when the thread has no messages or the endpoint doesn't compute activity enrichment.", + "example": "Alice Chen", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the thread. Shape is application-defined; `null` if no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "muted": { + "description": "Whether the authenticated user has muted notifications for this thread. `true` suppresses all notification delivery.", + "example": true, + "type": "boolean" + }, + "org": { + "description": "ID of the organization this thread belongs to (`org_...`). `null` for threads outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent_message": { + "description": "The message that spawned this thread as a sub-thread. `null` for top-level threads.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "example": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "items": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "example": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "items": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "example": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "items": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "example": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "items": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "participant": { + "description": "Array of participant user IDs (`usr_...`) who are members of this thread.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "participants": { + "description": "Expanded participant user objects for each member of this thread. Populated only when the association is loaded.", + "example": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "items": { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "participating_actor": { + "description": "Composite actor identifiers for all participants currently active in this thread. Present only when actor enrichment is requested.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "participating_agents": { + "description": "Expanded agent objects for all agents participating in this thread. Present only when agent enrichment is requested.", + "example": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "An AI agent that can be configured with tools, routines, and skills, and invoked to handle conversations or tasks.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints.", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "solution": { + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "role": { + "description": "The authenticated user's membership role in this thread, e.g. `\"owner\"`, `\"member\"`, or `\"viewer\"`. `null` if the user is not a member.", + "example": "member", + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this thread is scoped to (`dsb_...`). `null` for production threads.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "settings": { + "description": "Per-thread configuration settings controlling AI agent behavior for this thread.", + "example": { + "agent_enabled": true + }, + "properties": { + "agent_enabled": { + "description": "Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured.", + "example": true, + "type": "boolean" + } + }, + "type": "object" + }, + "slug": { + "description": "URL-safe slug for the thread, used in human-readable permalinks. `null` if not assigned.", + "example": "example-slug", + "type": "string" + }, + "sub_threads": { + "description": "Threads that are nested under this thread as replies to a parent message. Present only when sub-thread enrichment is requested.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "tags": { + "description": "Status tags on the thread (e.g. `\"blocked\"`, `\"needs-review\"`). Edited by any thread participant via the `/threads/:thread/tags` endpoints and filterable on the thread list endpoints. Empty array if none set.", + "example": [ + "blocked", + "needs-review" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this thread (`team_...`). `null` for user-owned or agent-owned threads.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "title": { + "description": "Human-readable name of the thread. `null` if no title has been set.", + "example": "Example Title", + "type": "string" + }, + "ttl": { + "description": "Time-to-live in seconds after which the thread may be automatically cleaned up. `null` if the thread does not expire.", + "example": 3600, + "type": "integer" + }, + "unread_count": { + "description": "Number of messages in this thread that the authenticated user has not yet read. Present only when read-state enrichment is requested.", + "example": 5, + "type": "integer" + }, + "updated_at": { + "description": "When the thread was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user who owns this thread (`usr_...`). `null` for team-owned or agent-owned threads.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "visibility": { + "description": "Who can read the thread: `team` for every owning-team member, `restricted` for team-readable threads with an explicit roster, or `private` for roster-only access.", + "enum": [ + "team", + "restricted", + "private" + ], + "example": "team", + "type": "string" + } + }, + "required": [ + "id", + "visibility" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Team not found" + } + }, + "summary": "List threads for a team", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new thread owned by the specified team. The authenticated caller must\nhave access to the team; requests from callers without team access are rejected\nwith 404.\n\nIf a `profile_picture` is provided in the thread params, it must be\nbase64-encoded image data. The image is uploaded and associated with the thread\nbefore creation completes. Omit `profile_picture` to skip this step.\n\nBy default the platform sends an automatic welcome message into the new thread.\nPass `skip_welcome_message: true` to suppress this behavior, for example when\ncreating threads programmatically in bulk or seeding test data.\n", + "operationId": "post_api_v1_teams__team_threads", + "parameters": [ + { + "description": "Team ID (`tem_...`) that will own the created thread.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "skip_welcome_message": true, + "thread": { + "create_legacy_agent": true, + "description": "An example description.", + "is_unlisted": true, + "key": "string", + "members": [ + { + "id": "string", + "type": "user" + } + ], + "metadata": { + "key": "value" + }, + "muted": true, + "org_id": "string", + "profile_picture": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "title": "Example Title", + "visibility": "team" + } + }, + "properties": { + "skip_welcome_message": { + "description": "When `true`, suppresses the automatic welcome message that is otherwise sent into the thread on creation. Defaults to `false`.", + "example": true, + "type": "boolean" + }, + "thread": { + "description": "Attributes for the new thread. See ThreadCreateParams for available fields.", + "example": { + "create_legacy_agent": true, + "description": "An example description.", + "is_unlisted": true, + "key": "string", + "members": [ + { + "id": "string", + "type": "user" + } + ], + "metadata": { + "key": "value" + }, + "muted": true, + "org_id": "string", + "profile_picture": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "title": "Example Title", + "visibility": "team" + }, + "properties": { + "create_legacy_agent": { + "description": "When `true`, provisions a legacy chat agent alongside the thread. Only needed for integrations that depend on the pre-v2 agent model.", + "example": true, + "type": "boolean" + }, + "description": { + "description": "Optional longer description of the thread's purpose. `null` if not provided.", + "example": "An example description.", + "type": "string" + }, + "is_unlisted": { + "description": "When `true`, the thread is hidden from the default thread list and accessible only by direct link or ID.", + "example": true, + "type": "boolean" + }, + "key": { + "description": "Client-assigned unique key for idempotent creation or later lookup. Must be unique within the owning organization.", + "example": "string", + "type": "string" + }, + "members": { + "description": "Users and agents to add atomically when the thread is created. Each target must pass the same authorization rules as a post-creation member add. Slack mirror threads reject non-empty caller-supplied rosters because their membership is sync-owned.", + "example": [ + { + "id": "string", + "type": "user" + } + ], + "items": { + "description": "A user or agent to add atomically when the thread is created.", + "example": { + "id": "string", + "type": "user" + }, + "properties": { + "id": { + "description": "Public user (`usr_...`) or agent (`agt_...`) ID matching `type`.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Member kind. Use `user` for a user ID or `agent` for an agent ID.", + "enum": [ + "user", + "agent" + ], + "example": "user", + "type": "string" + } + }, + "required": [ + "type", + "id" + ], + "type": "object" + }, + "type": "array" + }, + "metadata": { + "description": "Arbitrary key-value pairs stored alongside the thread. Values must be strings or numbers.", + "example": { + "key": "value" + }, + "type": "object" + }, + "muted": { + "description": "When `true`, push and in-app notifications for this thread are suppressed for the creating user.", + "example": true, + "type": "boolean" + }, + "org_id": { + "description": "ID of the organization to create the thread under. Defaults to the authenticated user's primary organization when omitted.", + "example": "string", + "type": "string" + }, + "profile_picture": { + "description": "Optional profile image for the thread, provided as a base64-encoded payload.", + "example": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "properties": { + "data": { + "description": "Base64-encoded image bytes.", + "example": "string", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded image, used for display and content-type inference.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`.", + "example": "application/json", + "type": "string" + } + }, + "type": "object" + }, + "settings": { + "description": "Configuration overrides for the thread, such as AI model selection and context window settings.", + "example": { + "agent_enabled": true + }, + "properties": { + "agent_enabled": { + "description": "Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured.", + "example": true, + "type": "boolean" + } + }, + "type": "object" + }, + "slug": { + "description": "Optional URL-safe identifier. Derived from the title when omitted and unique within the thread owner.", + "example": "example-slug", + "type": "string" + }, + "title": { + "description": "Display name for the thread. `null` if omitted, which causes the thread to be untitled.", + "example": "Example Title", + "type": "string" + }, + "visibility": { + "description": "Thread visibility. A team-owned thread with members must explicitly use `restricted` or `private`. User- and agent-owned threads with members default to `private` and reject every other value.", + "enum": [ + "team", + "restricted", + "private" + ], + "example": "team", + "type": "string" + } + }, + "type": "object" + } + }, + "required": [ + "thread" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Thread" + } + } + }, + "description": "The newly created thread." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Team not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create a thread for a team", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/teams/{team}/threads/metrics": { + "get": { + "description": "Returns how many **network-public** team threads were created in the UTC-day\nwindow. Counts come from realtime SQL aggregation over append-only\n`network_activity_events` (`thread.created` rows co-committed with create):\nteam- or restricted-visibility threads (plus legacy open-team rows), never\nprivate or mirror. Every Network member sees the same number. Hard-delete\nco-commits a separate `thread.deleted` transition event and does not remove\ncreate events (metric is \"created\", not \"still present\"). Visibility flips\nafter insert are ignored in v1.\n\nAny authenticated team member may read this count-only Network summary.\nRequests from callers without team access return 404 so team existence is\nnot disclosed.\n", + "operationId": "get_api_v1_teams__team_threads_metrics", + "parameters": [ + { + "description": "Team ID (`tem_...`) whose thread metrics should be returned.", + "example": "string", + "in": "path", + "name": "team", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "UTC-day window. One of 7, 30, 90, or 365; defaults to 30.", + "example": 1, + "in": "query", + "name": "days", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Network-scoped threads-created count.", + "example": { + "days": 1, + "end_at": "2024-01-01T00:00:00Z", + "opened": 1, + "start_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "days": { + "example": 1, + "type": "integer" + }, + "end_at": { + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "opened": { + "example": 1, + "type": "integer" + }, + "start_at": { + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "days", + "start_at", + "end_at", + "opened" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Team not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "Get threads-created count for a team", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/thread_messages/{message}": { + "delete": { + "description": "Permanently removes the specified message from its thread. This action\ncannot be undone.\n\nA message may be deleted by its author, an admin of the org the message\nbelongs to, an admin of the team that owns the thread, or the agent that\nsent it. Service-to-service callers with elevated (`all_powerful`) scope\nmay delete any message in a thread they can access. Returns\n`403 Forbidden` when the caller is not permitted to delete the message.\n", + "operationId": "delete_api_v1_thread_messages__message", + "parameters": [ + { + "description": "ID of the message to delete (`msg_...`).", + "example": "string", + "in": "path", + "name": "message", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty body. The server responds with HTTP 204 No Content on success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Message not found" + }, + "422": { + "description": "Delete failed" + } + }, + "summary": "Delete a thread message", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns a single message by its globally unique message ID. The authenticated\nviewer must be able to read the message and its thread.\n\nThe response includes the message's content, sender information, and any\nattachments that were loaded at creation time. For admin-authenticated\nrequests, an additional `admin` field is returned containing raw metadata\nand the associated trajectory data (LLM input/output messages) if one exists.\nA trajectory belongs to the agent response it produced, so `admin.trajectory`\nis only populated on the response message. On the triggering user message\nthe trajectory is omitted and `admin.response_message` links to the agent\nresponse (where the trajectory is shown), when a response exists.\n\nIf the message is not found or is not visible to the caller, a 404 is\nreturned.\n", + "operationId": "get_api_v1_thread_messages__message", + "parameters": [ + { + "description": "Globally unique message ID (`msg_...`).", + "example": "string", + "in": "path", + "name": "message", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ThreadMessage" + } + } + }, + "description": "The requested message, including its content, sender, and attachments." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App scope required" + }, + "404": { + "description": "Message not found or inaccessible" + } + }, + "summary": "Retrieve a message", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "put": { + "description": "Edits an existing thread message and returns the updated message object.\n\nA regular user may only edit messages they authored. Service-to-service\ncallers with elevated (`all_powerful`) scope may edit any accessible message\nwithout an ownership check. Returns `403 Forbidden` when the caller does not\nown the message.\n", + "operationId": "put_api_v1_thread_messages__message", + "parameters": [ + { + "description": "ID of the message to update (`msg_...`).", + "example": "string", + "in": "path", + "name": "message", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "content": "string", + "metadata": { + "key": "value" + }, + "type": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for a private message (replace or patch grants). Only valid when the message is already `private`. Omit to leave unchanged.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "content": { + "description": "Replacement text content for the message. Omit to leave the content unchanged.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Replacement key-value metadata. Keys beginning with `sys:` are reserved and stripped.", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Replacement client-defined classification. Free-form string up to 64 characters; platform-reserved values such as `system` are rejected.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Create-time message visibility. Supplying the existing value is harmless, but changing between `default` and `private` returns 422.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Message" + } + } + }, + "description": "The updated message object." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Message not found" + }, + "422": { + "description": "Update failed" + } + }, + "summary": "Update a thread message", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/thread_messages/{message}/reactions": { + "delete": { + "description": "Removes the authenticated user's emoji reaction from the specified thread\nmessage. The reaction is identified by the combination of the message ID and\nthe emoji; only the reaction belonging to the calling user is removed.\n\nReturns 204 No Content on success. Returns 404 if no matching reaction\nexists for the user and emoji on that message, or if the message itself\ncannot be found. The authenticated user must have read access to the thread\ncontaining the message.\n", + "operationId": "delete_api_v1_thread_messages__message_reactions", + "parameters": [ + { + "description": "Message ID (`msg_...`) of the thread message whose reaction should be removed.", + "example": "string", + "in": "path", + "name": "message", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response body. HTTP 204 No Content on success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Message not found" + }, + "422": { + "description": "Remove reaction failed" + } + }, + "summary": "Remove a reaction from a thread message", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Adds an emoji reaction to the specified thread message on behalf of the\nauthenticated user. If the user has already reacted to the message with the\nsame emoji, the request returns a 409 Conflict rather than creating a\nduplicate.\n\nThe authenticated user must have read access to the thread containing the\nmessage. If the thread belongs to a team, the user must be a member of\nthat team.\n", + "operationId": "post_api_v1_thread_messages__message_reactions", + "parameters": [ + { + "description": "Message ID (`msg_...`) of the thread message to react to.", + "example": "string", + "in": "path", + "name": "message", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "emoji": "string" + }, + "properties": { + "emoji": { + "description": "Emoji character or shortcode to add as a reaction, e.g. `\"👍\"` or `\":thumbsup:\"`.", + "example": "string", + "type": "string" + } + }, + "required": [ + "emoji" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "The newly created reaction.", + "example": { + "data": { + "created_at": "2024-01-01T00:00:00Z", + "feedback_type": "emoji_reaction", + "id": "umf_0aBcDeFgHiJkLmNoPqRsTu", + "message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "payload": { + "key": "value" + }, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + }, + "properties": { + "data": { + "description": "Reaction object that was created.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "feedback_type": "emoji_reaction", + "id": "umf_0aBcDeFgHiJkLmNoPqRsTu", + "message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "payload": { + "key": "value" + }, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "created_at": { + "description": "When the reaction was added (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "feedback_type": { + "description": "Category of feedback. Currently `\"emoji_reaction\"` for emoji responses.", + "example": "emoji_reaction", + "type": "string" + }, + "id": { + "description": "Reaction ID (`umf_...`).", + "example": "umf_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "message": { + "description": "ID of the message this reaction is attached to (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "payload": { + "description": "Structured data for the reaction. For `\"emoji_reaction\"` types, includes an `emoji` key with the Unicode emoji string.", + "example": { + "key": "value" + }, + "type": "object" + }, + "updated_at": { + "description": "When the reaction was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user who added the reaction (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Message not found" + }, + "422": { + "description": "Add reaction failed" + } + }, + "summary": "Add a reaction to a thread message", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/thread_messages/{message}/replies": { + "get": { + "description": "Returns a cursor-paginated list of reply messages for the specified thread\nmessage. By default only direct (first-level) replies are returned. Set\n`tree` to `true` to retrieve the full nested reply tree in a flat list,\nordered by creation time ascending.\n\nThe authenticated user must have access to the thread that contains the\nmessage. If the message belongs to a team-scoped thread, the viewer is\nautomatically scoped to that team before the query executes.\n\nUse `before_cursor` and `after_cursor` together with `limit` to page\nthrough large reply threads. The `has_more` field in the response\nindicates whether additional pages exist.\n", + "operationId": "get_api_v1_thread_messages__message_replies", + "parameters": [ + { + "description": "ID of the thread message to fetch replies for (`msg_...`).", + "example": "string", + "in": "path", + "name": "message", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Opaque pagination cursor. Returns replies created before this point. Obtain from `before_cursor` in a previous response.", + "example": "string", + "in": "query", + "name": "before_cursor", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Opaque pagination cursor. Returns replies created after this point. Obtain from `after_cursor` in a previous response.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of replies to return per page. Defaults to 20.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "When `true`, returns all replies in the nested reply tree (flattened). When `false` or omitted, returns only direct replies to the message.", + "example": true, + "in": "query", + "name": "tree", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedReplies" + } + } + }, + "description": "Cursor-paginated list of reply messages for the requested thread message." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Message not found" + }, + "422": { + "description": "Query failed" + } + }, + "summary": "List replies to a thread message", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/threads/{thread}": { + "delete": { + "description": "Permanently deletes a thread and all of its messages and artifacts. This action\ncannot be undone.\n\nThe authenticated user must own the thread or be an owner of the team the thread\nbelongs to. Attempting to delete a thread owned by another user or team returns 403.\n", + "operationId": "delete_api_v1_threads__thread", + "parameters": [ + { + "description": "Thread ID (`thr_...`). The authenticated user must own this thread.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response on successful deletion." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + } + }, + "summary": "Delete a thread", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns the full thread record for the given thread ID. The authenticated user\nmust own the thread or be a member of the workspace it belongs to.\n\nUse this endpoint to fetch the current state of a single thread, including its\ntitle, description, and metadata. To list many threads, use the list endpoint\nwith cursor-based pagination.\n", + "operationId": "get_api_v1_threads__thread", + "parameters": [ + { + "description": "Thread ID (`thr_...`). The authenticated user must have access to this thread.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Thread" + } + } + }, + "description": "The requested thread object." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + } + }, + "summary": "Retrieve a thread", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "put": { + "description": "Updates one or more mutable properties of the specified thread and returns\nthe full thread object with the applied changes. Only the fields you provide\nare modified; omitted fields retain their current values.\n\nIf `profile_picture` is supplied, the image is uploaded before the other\nfields are saved, after all ordinary thread fields have passed validation.\nSupplying invalid base64 picture data returns 422 and no other fields are\nupdated.\n\nVisibility can only widen: `private` may become `restricted` or `team`, and\n`restricted` may become `team`. The authenticated viewer must have\npermission to modify the thread.\n\nMirror-thread titles, descriptions, and notification state remain editable\nby privileged app viewers. Mirror metadata, visibility, and membership are\nprovider-managed and cannot be changed through this endpoint.\n", + "operationId": "put_api_v1_threads__thread", + "parameters": [ + { + "description": "Thread ID (`thr_...`). The authenticated user must have permission to update this thread.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "description": "An example description.", + "metadata": { + "key": "value" + }, + "muted": true, + "profile_picture": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "title": "Example Title", + "visibility": "private" + }, + "properties": { + "description": { + "description": "Optional longer text describing the thread's purpose. Replaces the existing description when provided.", + "example": "An example description.", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata to store on the thread. Merged with or replaces existing metadata.", + "example": { + "key": "value" + }, + "type": "object" + }, + "muted": { + "description": "When `true`, suppresses notifications for new messages in this thread for the authenticated user.", + "example": true, + "type": "boolean" + }, + "profile_picture": { + "description": "New profile picture for the thread. Provide all three inner fields to replace the existing image.", + "example": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "properties": { + "data": { + "description": "Base64-encoded image payload. Must be a valid base64 string.", + "example": "string", + "type": "string" + }, + "filename": { + "description": "Original filename of the image, e.g. `\"avatar.png\"`. Used for storage metadata.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/jpeg\"` or `\"image/png\"`.", + "example": "application/json", + "type": "string" + } + }, + "type": "object" + }, + "title": { + "description": "Human-readable display name for the thread. Replaces the existing title when provided.", + "example": "Example Title", + "type": "string" + }, + "visibility": { + "description": "Widen a team-owned thread: `private` may become `restricted` or `team`, and `restricted` may become `team`. Visibility cannot be narrowed.", + "enum": [ + "private", + "restricted", + "team" + ], + "example": "private", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Thread" + } + } + }, + "description": "The thread object after the update has been applied." + }, + "400": { + "description": "Invalid parameters" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Update a thread", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/threads/{thread}/agents": { + "get": { + "description": "Returns the agents participating in the specified thread. Only personal user\nthreads (threads owned by a single user, not a team) expose agents through\nthis endpoint; requests for team threads return 404.\n\nThe authenticated user must have visibility into the thread. Each agent entry\nincludes display information such as name and profile picture. Thread-level\noverrides (e.g. a custom name or profile picture set for this thread) take\nprecedence over the agent's default values. When the caller is the thread\nowner, each entry also includes an `agent_config` object describing the\nagent's message policy and context configuration.\n", + "operationId": "get_api_v1_threads__thread_agents", + "parameters": [ + { + "description": "Thread ID (`thr_...`). Must be a personal user thread visible to the authenticated user.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "The list of agents participating in the thread.", + "example": { + "data": [ + {} + ] + }, + "properties": { + "data": { + "description": "Array of agent objects for the thread. Each object includes `id`, `name`, `alias`, `profile_picture`, and `metadata`. Thread owners also receive an `agent_config` object with the agent's policy type and context configuration.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + } + }, + "summary": "List agents in a thread", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/threads/{thread}/artifacts": { + "get": { + "description": "Returns all artifacts produced during a thread's AI conversation. Artifacts are\nstructured outputs such as code files, documents, or generated assets created\nby the AI agent in response to messages in the thread.\n\nThe authenticated user must have access to the specified thread. Results are\nreturned in a single page; there is no cursor-based pagination for this endpoint.\n", + "operationId": "get_api_v1_threads__thread_artifacts", + "parameters": [ + { + "description": "Thread ID (`thr_...`). Must be accessible to the authenticated user.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Artifact listing for the thread.", + "example": { + "data": [ + { + "agent": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "current_version": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "file": "string", + "file_name": "Example Name", + "file_url": "https://example.com", + "id": "art_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + } + ] + }, + "properties": { + "data": { + "description": "Array of artifact objects produced during the thread's conversation.", + "example": [ + { + "agent": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "current_version": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "file": "string", + "file_name": "Example Name", + "file_url": "https://example.com", + "id": "art_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + } + ], + "items": { + "description": "A versioned artifact produced or managed by an agent, such as a generated file, report, or code output.", + "example": { + "agent": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "current_version": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "file": "string", + "file_name": "Example Name", + "file_url": "https://example.com", + "id": "art_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + }, + "properties": { + "agent": { + "description": "ID of the agent that produced this artifact (`agt_...`). `null` if not agent-produced.", + "example": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "content_type": { + "description": "MIME type of the current version's file, e.g. `\"text/csv\"` or `\"image/png\"`. `null` if no file is attached.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When the artifact was first created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "current_version": { + "description": "ID of the current (latest published) artifact version (`artv_...`). `null` if no version has been published.", + "example": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "description": { + "description": "Optional longer description of the artifact's contents or purpose. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "file": { + "description": "Storage file ID for the current version (`fil_...`). `null` if no file is attached.", + "example": "string", + "type": "string" + }, + "file_name": { + "description": "Original filename of the current version's file, e.g. `\"output.csv\"`. `null` if no file is attached.", + "example": "Example Name", + "type": "string" + }, + "file_url": { + "description": "Short-lived signed URL for downloading the current version's file. `null` if no file is attached.", + "example": "https://example.com", + "type": "string" + }, + "id": { + "description": "Artifact ID (`art_...`).", + "example": "art_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Image source metadata for rendering the current version's file inline. Present only when `content_type` starts with `\"image/\"`. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "description": "Human-readable name for the artifact, e.g. `\"Q2 Report\"`. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this artifact belongs to (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Identifier of the sandbox environment associated with this artifact. `null` if not sandbox-scoped.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this artifact (`tea_...`). `null` if not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread in which this artifact was created (`thr_...`). `null` if not thread-scoped.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the artifact record was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user who created this artifact (`usr_...`). `null` if not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "version": { + "description": "Current version number of the artifact. Increments each time a new version is published.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + } + }, + "summary": "List artifacts for a thread", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/threads/{thread}/mark_read": { + "post": { + "description": "Records that a user has read up to a specific message in the thread. Unread\nindicators and badge counts are cleared up to the specified message.\n\nYou must supply exactly one of `last_read_message` or `use_latest_message`.\nOmitting both returns 400. If `use_latest_message` is `true` and the thread\nhas no messages, the request succeeds silently with no state change.\n\nFor server-to-server (S2S) requests where no user identity is present in the\ntoken, the `user` param is required to identify whose read state to update.\n", + "operationId": "post_api_v1_threads__thread_mark_read", + "parameters": [ + { + "description": "Thread ID (`thr_...`). The thread to mark as read.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "last_read_message": "string", + "use_latest_message": true, + "user": "string" + }, + "properties": { + "last_read_message": { + "description": "Message ID (`msg_...`) to record as the last read message. Mutually exclusive with `use_latest_message`.", + "example": "string", + "type": "string" + }, + "use_latest_message": { + "description": "When `true`, marks the thread as read up to the latest message. Mutually exclusive with `last_read_message`.", + "example": true, + "type": "boolean" + }, + "user": { + "description": "User ID (`usr_...`) whose read state to update. Required for S2S requests; ignored when an authenticated user is present in the token.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Empty response on success." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Thread not found" + }, + "422": { + "description": "Validation error" + } + }, + "summary": "Mark a thread as read", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/threads/{thread}/members": { + "delete": { + "description": "Removes a user or agent from the explicit roster of a private or restricted\nthread. Team-visible threads use implicit membership and reject individual\nremovals. A member may remove themself; removing someone else requires\npermission to modify the thread. A successful removal returns HTTP 204 with\nno response body.\n\nSupply either `user` or `agent` depending on the value of `type`. Returns 404\nif the thread or the membership record does not exist.\n", + "operationId": "delete_api_v1_threads__thread_members", + "parameters": [ + { + "description": "Thread ID (`thr_...`) identifying the thread to remove the member from.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Empty response body. HTTP 204 on success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - not allowed to remove this member" + }, + "404": { + "description": "Thread or member not found" + }, + "422": { + "description": "Failed to remove member" + } + }, + "summary": "Remove a member from a thread", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "get": { + "description": "Returns all current user and agent members. Private and restricted threads\nreturn their explicit roster; team-visible threads return the owning team's\nimplicit roster. The authenticated viewer must be able to see the thread.\n\nResults are returned as a flat array in the `data` field. The list is not\npaginated — all members are returned in a single response.\n", + "operationId": "get_api_v1_threads__thread_members", + "parameters": [ + { + "description": "Thread ID (`thr_...`) whose members should be returned.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Object containing the thread's membership list.", + "example": { + "data": [ + { + "agent": { + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "joined_at": "2024-01-01T00:00:00Z", + "member_type": "user", + "membership_type": "owner", + "role": "owner", + "type": "user", + "user": { + "email": "user@example.com", + "full_name": "Example Name", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu" + } + } + ] + }, + "properties": { + "data": { + "description": "Array of thread member objects representing all current members of the thread.", + "example": [ + { + "agent": { + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "joined_at": "2024-01-01T00:00:00Z", + "member_type": "user", + "membership_type": "owner", + "role": "owner", + "type": "user", + "user": { + "email": "user@example.com", + "full_name": "Example Name", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu" + } + } + ], + "items": { + "description": "A roster-safe thread member for the dedicated thread-members endpoint.\n\nThe nested user and agent identities are deliberately trimmed so listing a\nvisible thread never exposes account metadata or agent configuration.\n", + "example": { + "agent": { + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "joined_at": "2024-01-01T00:00:00Z", + "member_type": "user", + "membership_type": "owner", + "role": "owner", + "type": "user", + "user": { + "email": "user@example.com", + "full_name": "Example Name", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu" + } + }, + "properties": { + "agent": { + "description": "Roster-safe agent identity. Populated for agent members; `null` for users.", + "example": { + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "email": { + "description": "Agent email address. `null` if not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "name": { + "description": "Human-readable agent name. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization that owns this agent (`org_...`). `null` if not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "team": { + "description": "Team that owns this agent (`tem_...`). `null` if not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "user": { + "description": "User that owns this agent (`usr_...`). `null` if not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "joined_at": { + "description": "When this member joined the thread (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "member_type": { + "description": "Backward-compatible alias of `type`.", + "example": "user", + "type": "string" + }, + "membership_type": { + "description": "Role of this member, commonly `\"owner\"` or `\"member\"`.", + "example": "owner", + "type": "string" + }, + "role": { + "description": "Backward-compatible alias of `membership_type`.", + "example": "owner", + "type": "string" + }, + "type": { + "description": "Kind of participant. One of `\"user\"` or `\"agent\"`.", + "example": "user", + "type": "string" + }, + "user": { + "description": "Roster-safe user identity. Populated for user members; `null` for agents.", + "example": { + "email": "user@example.com", + "full_name": "Example Name", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "email": { + "description": "User's email address. `null` if not set.", + "example": "user@example.com", + "type": "string" + }, + "full_name": { + "description": "Backward-compatible alias of `name`. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "name": { + "description": "Full display name of the user. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization this user belongs to (`org_...`). `null` if the user is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + } + }, + "summary": "List members of a thread", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Adds a user or agent to the explicit roster of a private or restricted\nthread. Team-visible threads use the owning team's implicit roster and reject\nexplicit additions. On restricted threads, a team member may add themself;\nadding anyone else requires permission to modify the thread.\n\nSupply either `user` or `agent` depending on the value of `type`. Targets\nmust be visible to the caller and, for an ordinary team-owned thread, must\nbelong to the owning team. On success the membership record is returned with\nHTTP 201; repeated agent additions are idempotent.\n", + "operationId": "post_api_v1_threads__thread_members", + "parameters": [ + { + "description": "Thread ID (`thr_...`) identifying the thread to add the member to.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "membership_type": "string", + "type": "string", + "user": "string" + }, + "properties": { + "agent": { + "description": "Agent ID of the principal to add. Required when `type` is `\"agent\"`.", + "example": "string", + "type": "string" + }, + "membership_type": { + "description": "Role granted to the new member. One of `\"owner\"` or `\"member\"`. Defaults to `\"member\"`.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Kind of principal being added. Must be `\"user\"` or `\"agent\"`.", + "example": "string", + "type": "string" + }, + "user": { + "description": "User ID of the principal to add. Required when `type` is `\"user\"`.", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatMember" + } + } + }, + "description": "The user or agent membership that was added to the thread." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - not allowed to add members to this thread" + }, + "404": { + "description": "Thread not found" + }, + "422": { + "description": "Failed to add member" + } + }, + "summary": "Add a member to a thread", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/threads/{thread}/messages": { + "get": { + "description": "Returns a cursor-paginated list of messages belonging to the specified thread,\nordered from oldest to newest. Supply `before_cursor`, `after_cursor`, or both\nto page through or bound the result set; omit both to receive the most recent page.\nSupply `anchor` and `direction` to fetch a window before, after, or around a\nspecific message. Use `anchor=last_matching&anchor_agent_mode=embedded` to\nresolve the anchor from the latest embedded-agent message, and add\n`anchor_agent` to scope that resolution to a single sender agent.\nSupply `metadata` as a JSON-encoded structured expression to filter message\nmetadata before cursor pagination or anchored window limits are applied.\n\nThe authenticated user must have access to the thread's owner (workspace or user).\nA 403 is returned if the thread exists but is not accessible to the caller; a 404\nis returned if the thread does not exist or is not visible to the authenticated user.\n\nPass `include_reply_counts: true` to annotate each message with the number of\nthreaded replies it has received. This adds a small amount of latency and should\nbe omitted when reply counts are not needed.\n", + "operationId": "get_api_v1_threads__thread_messages", + "parameters": [ + { + "description": "Thread ID (`thr_...`). The authenticated user must have access to this thread.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Opaque cursor returned in a previous response's `before_cursor` field. When provided, returns messages immediately before that position. May be combined with `after_cursor` to bound a range.", + "example": "string", + "in": "query", + "name": "before_cursor", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Opaque cursor returned in a previous response's `after_cursor` field. When provided, returns messages immediately after that position. May be combined with `before_cursor` to bound a range.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Structured metadata filter expression. Only messages whose `metadata` object satisfies the expression are returned. The filter is applied before cursor pagination and anchored window limits.", + "in": "query", + "name": "metadata", + "required": false, + "schema": { + "description": "A recursive boolean expression tree for filtering records by their JSON metadata field.\n\nEach node is either a group (`and`, `or`, `not`) with nested `clauses`, or a leaf\npredicate (`eq`, `contains`, `exists`) that targets a specific path inside the\nmetadata object. Leaf predicates use `path` (an array of key segments) to address\nnested values.\n\nOperator notes:\n- `eq` performs deep JSONB equality on the value at `path`.\n- `contains` checks whether the stored metadata structurally contains the given value;\n this is the only operator backed by the GIN index and is preferred for performance.\n- `exists` checks whether `path` is present in the metadata object; a key whose value\n is explicitly `null` still satisfies this predicate.\n- `and` and `or` accept two or more `clauses`; `not` accepts exactly one.\n\nThe legacy flat shape (`type: \"metadata\"`, `key`, `value`) is still accepted and is\ntreated as an `eq` predicate. Prefer the structured form for new integrations.\n", + "examples": [ + { + "clauses": [ + { + "operator": "eq", + "path": [ + "type" + ], + "value": "agent_network" + }, + { + "clauses": [ + { + "operator": "exists", + "path": [ + "collaborations", + "org_123" + ] + }, + { + "operator": "eq", + "path": [ + "customer_tier" + ], + "value": "enterprise" + } + ], + "operator": "or" + } + ], + "operator": "and" + } + ], + "properties": { + "clause": { + "description": "Single child expression node. Alternative to `clauses` when `operator` is `not`.", + "type": "object" + }, + "clauses": { + "description": "Array of child expression nodes. Required for `and` and `or` (two or more items) and `not` (exactly one item).", + "items": { + "type": "object" + }, + "type": "array" + }, + "key": { + "deprecated": true, + "description": "Deprecated. Top-level metadata key; equivalent to a single-element `path`. Use `path` instead.", + "type": "string" + }, + "operator": { + "description": "The boolean group operator (`and`, `or`, `not`) or leaf predicate operator (`eq`, `contains`, `exists`) for this node.", + "enum": [ + "and", + "or", + "eq", + "contains", + "exists", + "not" + ], + "type": "string" + }, + "path": { + "description": "Ordered key segments addressing a nested location inside the metadata object, e.g. `[\"collaborations\", \"org_123\"]`.", + "items": { + "type": "string" + }, + "type": "array" + }, + "type": { + "deprecated": true, + "description": "Deprecated. Legacy discriminator; `type: \"metadata\"` combined with `key`/`value` is treated as an `eq` predicate. Use `operator` instead.", + "type": "string" + }, + "value": { + "description": "The JSON value to compare against the node at `path`. Required for `eq` and `contains` predicates; omitted for `exists`." + } + }, + "type": "object" + } + }, + { + "description": "Maximum number of messages to return per page. Defaults to 20; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Message ID (`msg_...`) to use as a window anchor, or `last_matching` to resolve the anchor from the latest message matching the anchor filters. Cannot be combined with `before_cursor` or `after_cursor`.", + "example": "string", + "in": "query", + "name": "anchor", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Window direction relative to `anchor`. `before` returns older messages, `after` returns newer messages, and `around` returns messages on both sides. Defaults to `after` when `anchor` is supplied. `direction=around` cannot be combined with an explicit `limit`; use `before_limit` and `after_limit`.", + "example": "before", + "in": "query", + "name": "direction", + "required": false, + "schema": { + "enum": [ + "before", + "after", + "around" + ], + "type": "string" + } + }, + { + "description": "For `direction=around`, maximum number of messages older than the anchor. Defaults to 20; maximum is 100.", + "example": 1, + "in": "query", + "name": "before_limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "For `direction=around`, maximum number of messages newer than the anchor. Defaults to 20; maximum is 100.", + "example": 1, + "in": "query", + "name": "after_limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Whether to include the anchor message in a window response. Defaults to `true` for `direction=around`; ignored for ordinary cursor pagination and one-sided windows.", + "example": true, + "in": "query", + "name": "include_anchor", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "When `anchor=last_matching`, resolve the anchor from the latest message with this local agent execution mode.", + "example": "cli", + "in": "query", + "name": "anchor_agent_mode", + "required": false, + "schema": { + "enum": [ + "cli", + "embedded" + ], + "type": "string" + } + }, + { + "description": "When `anchor=last_matching`, scope the anchor resolution to messages sent by this agent (`agi_...`). Combine with `anchor_agent_mode` to resolve the latest message from a specific agent in a given mode.", + "example": "string", + "in": "query", + "name": "anchor_agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "When `true`, each message in the response is annotated with its threaded reply count. Defaults to `false`. Adds latency; omit when reply counts are not needed.", + "example": true, + "in": "query", + "name": "include_reply_counts", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Paginated list of messages for the requested thread.", + "example": { + "data": { + "after_cursor": "string", + "anchor": "string", + "before_cursor": "string", + "messages": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ] + } + }, + "properties": { + "data": { + "description": "Pagination envelope containing the messages for this page along with cursors for adjacent pages.", + "example": { + "after_cursor": "string", + "anchor": "string", + "before_cursor": "string", + "messages": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ] + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor to pass as `after` to retrieve the page of messages newer than this result set. `null` when there are no later messages.", + "example": "string", + "type": "string" + }, + "anchor": { + "description": "Message ID used as the anchor for a windowed query. `null` for ordinary cursor pagination.", + "example": "string", + "type": "string" + }, + "before_cursor": { + "description": "Opaque cursor to pass as `before` to retrieve the page of messages older than this result set. `null` when there are no earlier messages.", + "example": "string", + "type": "string" + }, + "messages": { + "description": "Ordered array of message objects for this page of results.", + "example": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ], + "items": { + "description": "A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "example": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "items": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "example": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "items": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "example": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "items": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "example": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "items": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "messages" + ], + "type": "object" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Bad request - invalid metadata filter" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + } + }, + "summary": "List messages in a thread", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/threads/{thread}/picture": { + "put": { + "description": "Uploads a new profile picture for the specified thread and returns the updated\nthread object. The image must be supplied as a base64-encoded string with its\nMIME type.\n\nThe authenticated user must own the thread or be a team owner of the workspace\nthe thread belongs to. Supplying invalid base64 data returns 422.\n", + "operationId": "put_api_v1_threads__thread_picture", + "parameters": [ + { + "description": "Thread ID (`thr_...`). The authenticated user must have permission to update this thread.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "picture": { + "data": "string", + "filename": "avatar.png", + "mime_type": "application/json" + } + }, + "properties": { + "picture": { + "description": "Profile picture payload. Must include the base64-encoded image data and its MIME type.", + "example": { + "data": "string", + "filename": "avatar.png", + "mime_type": "application/json" + }, + "properties": { + "data": { + "description": "Base64-encoded binary content of the image file.", + "example": "string", + "type": "string" + }, + "filename": { + "description": "Original filename of the image, e.g. `\"avatar.png\"`. Used for storage and display.", + "example": "avatar.png", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/jpeg\"` or `\"image/png\"`.", + "example": "application/json", + "type": "string" + } + }, + "required": [ + "data", + "mime_type", + "filename" + ], + "type": "object" + } + }, + "required": [ + "picture" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Thread" + } + } + }, + "description": "The thread object after the profile picture has been updated." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + }, + "422": { + "description": "Invalid base64 data" + } + }, + "summary": "Update a thread's profile picture", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/threads/{thread}/read_status": { + "get": { + "description": "Returns the read status of a thread for the specified user, including the ID\nof the last message they have read and the number of unread messages remaining.\n\nFor user-authenticated requests, the status is always returned for the\nauthenticated user and the `user` parameter is ignored. For server-to-server\n(S2S) requests, the `user` parameter is required and must be a valid user ID.\n\nReturns 404 if the thread does not exist or the caller does not have access\nto it.\n", + "operationId": "get_api_v1_threads__thread_read_status", + "parameters": [ + { + "description": "Thread ID (`thr_...`). Must be accessible to the authenticated user or, for S2S requests, to the specified user.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) whose read status to retrieve. Required for S2S requests; ignored for user-authenticated requests, which always return the status for the authenticated user.", + "example": "string", + "in": "query", + "name": "user", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ThreadReadStatus" + } + } + }, + "description": "The read status record for the requested thread and user." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + } + }, + "summary": "Retrieve a thread's read status", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/threads/{thread}/search": { + "get": { + "description": "Searches canonical message content in the specified thread. `\"text\"` mode\nperforms the existing case-insensitive substring search, `\"embedding\"` ranks\nstored message embeddings by cosine similarity, and `\"hybrid\"` combines the\ntext and embedding rankings with Reciprocal Rank Fusion (RRF). Only messages\nvisible to the authenticated caller are considered.\n\nResults are intentionally lean: each row contains only a bounded content\nsnippet, sender identity, and timestamp. Attachments, reactions, ACLs, and\nmetadata are neither hydrated nor serialized. At most 20 results are\nreturned. Text results support chronological cursor pagination. Embedding and\nhybrid results are relevance-ranked single pages and return null cursors.\n", + "operationId": "get_api_v1_threads__thread_search", + "parameters": [ + { + "description": "App ID (`app_...`). Required by the protected developer mount and omitted from the public mount.", + "example": "string", + "in": "query", + "name": "app", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Thread ID (`thr_...`). Must be visible to the authenticated caller.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Text or semantic search query. Must contain 3 to 200 characters after trimming.", + "example": "string", + "in": "query", + "name": "q", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of results. Defaults to 20 and is capped at 20.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Search algorithm: `text` for substring matching, `embedding` for cosine similarity, or `hybrid` for RRF over both rankings.", + "example": "text", + "in": "query", + "name": "mode", + "required": false, + "schema": { + "enum": [ + "text", + "embedding", + "hybrid" + ], + "type": "string" + } + }, + { + "description": "Text mode only. Opaque cursor returned by a previous page; fetches older matches.", + "example": "string", + "in": "query", + "name": "before_cursor", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Text mode only. Opaque cursor returned by a previous page; fetches newer matches.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "A bounded list of lean message search results.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "agent": "string", + "content": "string", + "created_at": "2024-01-01T00:00:00Z", + "id": "string", + "similarity_score": 1.0, + "user": "string" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "description": "Text-mode cursor for the next page of newer matches, or `null` for ranked modes and empty pages.", + "example": "string", + "type": "string" + }, + "before_cursor": { + "description": "Text-mode cursor for the next page of older matches, or `null` for ranked modes and empty pages.", + "example": "string", + "type": "string" + }, + "data": { + "description": "Matching messages ordered newest first in text mode and by relevance in embedding or hybrid mode.", + "example": [ + { + "agent": "string", + "content": "string", + "created_at": "2024-01-01T00:00:00Z", + "id": "string", + "similarity_score": 1.0, + "user": "string" + } + ], + "items": { + "description": "A lean message search result.\n\nSearch results intentionally omit attachment, reaction, ACL, and metadata\npayloads so searching a large thread does not hydrate its message history.\n", + "example": { + "agent": "string", + "content": "string", + "created_at": "2024-01-01T00:00:00Z", + "id": "string", + "similarity_score": 1.0, + "user": "string" + }, + "properties": { + "agent": { + "description": "Agent sender ID (`agi_...`), or `null` when a human sent the message.", + "example": "string", + "type": "string" + }, + "content": { + "description": "A bounded snippet around the first matching occurrence (at most 240 characters).", + "example": "string", + "type": "string" + }, + "created_at": { + "description": "When the message was posted.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "string", + "type": "string" + }, + "similarity_score": { + "description": "Cosine similarity to the query when the result participated in embedding search, or `null` in text mode and for text-only hybrid matches.", + "example": 1.0, + "type": "number" + }, + "user": { + "description": "Human sender ID (`usr_...`), or `null` when an agent sent the message.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "content", + "created_at" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "description": "`true` when at least one additional visible match exists.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Invalid cursor" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app." + }, + "404": { + "description": "Thread not found" + }, + "422": { + "description": "Invalid parameters" + }, + "502": { + "description": "Service unavailable" + } + }, + "summary": "Search messages in a thread", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/threads/{thread}/settings": { + "get": { + "description": "Returns the current settings for the specified thread. Settings control\nper-thread behavior such as whether the AI agent is enabled.\n\nThe authenticated user must own the thread or be a member of its workspace.\nIf settings have never been explicitly configured, defaults are returned\n(for example, `agent_enabled` defaults to `true`).\n", + "operationId": "get_api_v1_threads__thread_settings", + "parameters": [ + { + "description": "Thread ID (`thr_...`). Must belong to the authenticated user's workspace.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "The settings for the requested thread.", + "example": { + "agent_enabled": true + }, + "properties": { + "agent_enabled": { + "description": "Whether the AI agent is active for this thread. Defaults to `true` when no settings have been explicitly set.", + "example": true, + "type": "boolean" + } + }, + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + } + }, + "summary": "Retrieve thread settings", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "put": { + "description": "Updates the settings for the specified thread. Only fields included in\nthe `settings` map are modified; omitted fields retain their current values.\n\nThe authenticated user must own the thread or be a member of its workspace.\nReturns the full settings object reflecting the state after the update.\nValidation errors are returned as `422 Unprocessable Entity`.\n", + "operationId": "put_api_v1_threads__thread_settings", + "parameters": [ + { + "description": "Thread ID (`thr_...`). Must belong to the authenticated user's workspace.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "settings": {} + }, + "properties": { + "settings": { + "description": "Map of settings fields to update. Include only the keys you want to change.", + "example": {}, + "type": "object" + } + }, + "required": [ + "settings" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ThreadSettings" + } + } + }, + "description": "The thread settings object after the update has been applied." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + }, + "422": { + "description": "Validation error" + } + }, + "summary": "Update thread settings", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/threads/{thread}/tags": { + "delete": { + "description": "Removes one or more status tags from the thread and returns the updated\nthread. Removing a tag the thread does not have is a no-op.\n\nAny participant of the thread — a human member or an agent member — may edit\ntags. Supply the tags to remove as repeated query parameters, e.g.\n`?tags[]=blocked&tags[]=needs-review`.\n", + "operationId": "delete_api_v1_threads__thread_tags", + "parameters": [ + { + "description": "Thread ID (`thr_...`) to untag.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Thread" + } + } + }, + "description": "The thread object after the tags were removed." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + }, + "422": { + "description": "Invalid tags" + } + }, + "summary": "Remove tags from a thread", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Adds one or more status tags to the thread and returns the updated thread.\n\nAny participant of the thread — a human member or an agent member — may edit\ntags; this is broader than the owner/admin permission required to update other\nthread fields. Adding a tag the thread already has is a no-op. Tags are\nnormalized (trimmed and lowercased) and may contain only lowercase letters,\nnumbers, hyphens, and underscores.\n", + "operationId": "post_api_v1_threads__thread_tags", + "parameters": [ + { + "description": "Thread ID (`thr_...`) to tag.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "tags": [ + "string" + ] + }, + "properties": { + "tags": { + "description": "Tags to add to the thread.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "tags" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Thread" + } + } + }, + "description": "The thread object after the tags were added." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + }, + "422": { + "description": "Invalid tags" + } + }, + "summary": "Add tags to a thread", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "put": { + "description": "Replaces the thread's entire set of status tags with the provided list and\nreturns the updated thread. Passing an empty array clears all tags.\n\nAny participant of the thread — a human member or an agent member — may edit\ntags. Tags are normalized (trimmed and lowercased) and may contain only\nlowercase letters, numbers, hyphens, and underscores.\n", + "operationId": "put_api_v1_threads__thread_tags", + "parameters": [ + { + "description": "Thread ID (`thr_...`) to tag.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "tags": [ + "string" + ] + }, + "properties": { + "tags": { + "description": "The complete set of tags for the thread. An empty array clears all tags.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "tags" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Thread" + } + } + }, + "description": "The thread object after its tags were replaced." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + }, + "422": { + "description": "Invalid tags" + } + }, + "summary": "Replace a thread's tags", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/threads/{thread}/trajectories": { + "get": { + "description": "Returns a cursor-paginated list of thread message trajectories associated with the\nspecified thread. Each trajectory links a user message and its agent response to the\nunderlying AI trajectory record that captured the model's reasoning steps.\n\nThe authenticated user must own the thread or be a member of the workspace it belongs\nto. Results are returned in reverse chronological order by default. Use `before_cursor`\nand `after_cursor` to navigate pages; provide at most one cursor per request.\n\nOptionally filter results to trajectories produced in response to a specific message\nby supplying the `message` parameter. When no trajectories match the query, `data`\nis an empty array and both cursor fields are `null`.\n", + "operationId": "get_api_v1_threads__thread_trajectories", + "parameters": [ + { + "description": "Thread ID (`thr_...`). The authenticated user must own this thread or belong to its workspace.", + "example": "string", + "in": "path", + "name": "thread", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Opaque cursor from a previous response's `before_cursor` field. Returns the page of results preceding that cursor position.", + "example": "string", + "in": "query", + "name": "before_cursor", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Opaque cursor from a previous response's `after_cursor` field. Returns the page of results following that cursor position.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of trajectories to return per page. Defaults to 20; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Message ID (`msg_...`). When provided, limits results to trajectories associated with this specific message.", + "example": "string", + "in": "query", + "name": "message", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Paginated list of thread message trajectories for the requested page.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "agent_message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "id": "tmt_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "trajectory": "trj_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user_message": "msg_0aBcDeFgHiJkLmNoPqRsTu" + } + ] + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor to pass as `after_cursor` to retrieve the next page. `null` when no further pages exist.", + "example": "string", + "type": "string" + }, + "before_cursor": { + "description": "Opaque cursor to pass as `before_cursor` to retrieve the previous page. `null` when this is the first page.", + "example": "string", + "type": "string" + }, + "data": { + "description": "Array of thread message trajectory objects for the current page. Empty when no trajectories match the query.", + "example": [ + { + "agent_message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "id": "tmt_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "trajectory": "trj_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user_message": "msg_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "Links a pair of thread messages (user turn and agent reply) to the AI trajectory that produced the response, enabling replay and debugging of model interactions.", + "example": { + "agent_message": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "id": "tmt_0aBcDeFgHiJkLmNoPqRsTu", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "trajectory": "trj_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user_message": "msg_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent_message": { + "description": "ID of the agent-authored reply message (`msg_...`). `null` if the trajectory has not yet produced a response message.", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When this trajectory link was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Thread message trajectory ID (`tmt_...`).", + "example": "tmt_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org": { + "description": "ID of the organization this trajectory belongs to (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment in which this trajectory was produced (`dsb_...`). `null` in production contexts.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread containing the linked messages (`thr_...`).", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "trajectory": { + "description": "ID of the AI trajectory record that captures the full model interaction for this exchange (`trj_...`).", + "example": "trj_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When this trajectory link was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user_message": { + "description": "ID of the user-authored message that triggered the agent response (`msg_...`). `null` if the agent turn was not preceded by a user message.", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + } + }, + "summary": "List trajectories for a thread", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/trajectories/{trajectory}": { + "get": { + "description": "Returns the AI trajectory identified by `trajectory`. A trajectory captures\nthe model's full reasoning steps, messages, and metadata for a single AI\ninvocation, including references to the associated team, organization, sandbox,\nand storage file when present.\n\nThe authenticated user must have access to the trajectory. Trajectories are\nscoped to the workspace of the requesting user; attempting to access a\ntrajectory outside that scope returns 404.\n", + "operationId": "get_api_v1_trajectories__trajectory", + "parameters": [ + { + "description": "Trajectory ID (`trj_...`) of the trajectory to retrieve.", + "example": "string", + "in": "path", + "name": "trajectory", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Trajectory" + } + } + }, + "description": "The requested trajectory object." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Trajectory not found" + } + }, + "summary": "Retrieve a trajectory", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/trajectories/{trajectory}/contents": { + "get": { + "description": "Returns the raw JSON contents of the trajectory identified by `trajectory`.\nThe response body is the trajectory's stored content blob rendered directly\nas `application/json`, bypassing the standard schema serialization used by\nthe Show endpoint.\n\nUse this endpoint when you need the unprocessed trajectory data — for example,\nto replay or inspect model reasoning steps in full fidelity (eval grading).\nThe authenticated user must have access to the trajectory; trajectories\noutside the caller's workspace scope return 404.\n", + "operationId": "get_api_v1_trajectories__trajectory_contents", + "parameters": [ + { + "description": "Trajectory ID (`trj_...`) whose raw contents to retrieve.", + "example": "string", + "in": "path", + "name": "trajectory", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "format": "binary", + "type": "string" + } + } + }, + "description": "Raw trajectory JSON blob. The `Content-Type` header is `application/json`." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Trajectory not found" + } + }, + "summary": "Retrieve raw trajectory contents", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/users/me": { + "get": { + "description": "Returns the user associated with the authenticated session or bearer\ntoken. This is the canonical way to resolve \"who am I?\" after\nauthentication.\n\nThe response includes the user's profile, notification settings, and\nprofile picture, along with the app, organization, and sandbox the\ntoken is scoped to and their display names — enough to establish full\nsession context in a single call. Unauthenticated requests return 401.\n", + "operationId": "get_api_v1_users_me", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "description": "The authenticated user object." + }, + "401": { + "description": "Unauthorized" + } + }, + "summary": "Retrieve the current user", + "x-auth": [ + "publishable_key", + "bearer", + "device_flow" + ], + "x-required-scopes": [ + "profile" + ] + } + }, + "/api/v1/users/{user}": { + "get": { + "description": "Returns the user identified by `user`. The authenticated user must share\nat least one team with the target user; requests for users outside any\nshared team are rejected with 403.\n\nA user may always retrieve their own profile with this endpoint. Use the\n`GET /users/me` endpoint as a convenience alias for retrieving the\nauthenticated user without specifying an ID.\n", + "operationId": "get_api_v1_users__user", + "parameters": [ + { + "description": "User ID (`usr_...`) of the user to retrieve.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "description": "The requested user object." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "summary": "Retrieve a user by ID", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/users/{user}/artifacts": { + "get": { + "description": "Returns all artifacts owned by the specified user. Artifacts represent\nAI-generated or user-uploaded files associated with agent sessions,\nthreads, or sandboxes — such as images, documents, and code outputs.\n\nThe authenticated user must be requesting their own artifacts or must\nhave administrative access. Attempting to list artifacts for a user\nthe caller is not authorized to access returns 403.\n\nResults are returned in a single page without cursor pagination. Each\nartifact in the response reflects the state of its current version,\nincluding a short-lived signed `file_url` for direct download.\n", + "operationId": "get_api_v1_users__user_artifacts", + "parameters": [ + { + "description": "User ID (`usr_...`). The authenticated user must be this user or have access to their artifacts.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "All artifacts owned by the user.", + "example": { + "data": [ + { + "agent": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "current_version": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "file": "string", + "file_name": "Example Name", + "file_url": "https://example.com", + "id": "art_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + } + ] + }, + "properties": { + "data": { + "description": "Array of artifact objects belonging to the user.", + "example": [ + { + "agent": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "current_version": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "file": "string", + "file_name": "Example Name", + "file_url": "https://example.com", + "id": "art_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + } + ], + "items": { + "description": "A versioned artifact produced or managed by an agent, such as a generated file, report, or code output.", + "example": { + "agent": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "current_version": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "file": "string", + "file_name": "Example Name", + "file_url": "https://example.com", + "id": "art_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "version": 1 + }, + "properties": { + "agent": { + "description": "ID of the agent that produced this artifact (`agt_...`). `null` if not agent-produced.", + "example": "agt_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "content_type": { + "description": "MIME type of the current version's file, e.g. `\"text/csv\"` or `\"image/png\"`. `null` if no file is attached.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When the artifact was first created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "current_version": { + "description": "ID of the current (latest published) artifact version (`artv_...`). `null` if no version has been published.", + "example": "afv_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "description": { + "description": "Optional longer description of the artifact's contents or purpose. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "file": { + "description": "Storage file ID for the current version (`fil_...`). `null` if no file is attached.", + "example": "string", + "type": "string" + }, + "file_name": { + "description": "Original filename of the current version's file, e.g. `\"output.csv\"`. `null` if no file is attached.", + "example": "Example Name", + "type": "string" + }, + "file_url": { + "description": "Short-lived signed URL for downloading the current version's file. `null` if no file is attached.", + "example": "https://example.com", + "type": "string" + }, + "id": { + "description": "Artifact ID (`art_...`).", + "example": "art_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Image source metadata for rendering the current version's file inline. Present only when `content_type` starts with `\"image/\"`. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "description": "Human-readable name for the artifact, e.g. `\"Q2 Report\"`. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this artifact belongs to (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Identifier of the sandbox environment associated with this artifact. `null` if not sandbox-scoped.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team that owns this artifact (`tea_...`). `null` if not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread in which this artifact was created (`thr_...`). `null` if not thread-scoped.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the artifact record was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user who created this artifact (`usr_...`). `null` if not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "version": { + "description": "Current version number of the artifact. Increments each time a new version is published.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "summary": "List a user's artifacts", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/users/{user}/invites": { + "post": { + "description": "Creates a new invite for the authenticated user. The invite can optionally be\nscoped to a specific thread, a persona, or carry arbitrary metadata. The\ncaller receives the new invite object at HTTP 201.\n\nThe invite key is always generated server-side (192-bit URL-safe random\nstring) and cannot be supplied by the caller.\n\nThe path `:user` must match the authenticated user. If a `thread_id` is\nprovided, the authenticated user must have permission to invite others to that\nthread; team threads are not supported and return an error. Supplying a\n`thread_id` that does not exist or that belongs to a different user returns\nan error. If a key collision occurs during creation the call returns a 409\nconflict — simply retry to generate a new key.\n", + "operationId": "post_api_v1_users__user_invites", + "parameters": [ + { + "description": "User ID (`usr_...`). Must match the authenticated user.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "invite": { + "metadata": { + "key": "value" + }, + "persona_id": "string", + "thread_id": "string" + } + }, + "properties": { + "invite": { + "description": "Parameters for the new invite. See the UserInviteCreateParams schema for field details.", + "example": { + "metadata": { + "key": "value" + }, + "persona_id": "string", + "thread_id": "string" + }, + "properties": { + "metadata": { + "description": "Arbitrary key-value metadata to attach to the invite. Returned as-is on the resulting invite object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "persona_id": { + "description": "ID of the persona to associate with this invite (`per_...`). `null` if the invite is not bound to a persona.", + "example": "string", + "type": "string" + }, + "thread_id": { + "description": "ID of the thread to associate with this invite (`thr_...`). `null` if the invite is not bound to a thread.", + "example": "string", + "type": "string" + } + }, + "type": "object" + } + }, + "required": [ + "invite" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserInvite" + } + } + }, + "description": "The newly created invite object." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Thread not found" + }, + "409": { + "description": "Resource already exists" + }, + "422": { + "description": "Validation failed; Invites cannot be created for team threads; Invalid thread id; User context is required" + } + }, + "summary": "Create a user invite", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/users/{user}/orgs": { + "get": { + "description": "Returns the organizations the specified user belongs to. A user can belong\nto at most one organization, so the `data` array contains either zero or one\nitems.\n\nThe authenticated viewer must have permission to inspect the target user.\nReturns an empty `data` array when the user has no organization membership.\n", + "operationId": "get_api_v1_users__user_orgs", + "parameters": [ + { + "description": "User ID (`usr_...`) whose organization membership you want to retrieve.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "The user's organization memberships.", + "example": { + "data": [ + { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "domain": "acme.com", + "id": "org_0aBcDeFgHiJkLmNoPqRsTu", + "industry": "fintech", + "name": "Example Name", + "onboarding_solution_lookup_key": "string", + "onboarding_track": "vendor", + "owned_products": [ + "agent-rooms" + ], + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "status": "active", + "updated_at": "2024-01-01T00:00:00Z", + "vendor": { + "id": "org_0aBcDeFgHiJkLmNoPqRsTu", + "logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name" + }, + "website": "https://example.com" + } + ] + }, + "properties": { + "data": { + "description": "Array of organization objects the user belongs to. Contains at most one item.", + "example": [ + { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "domain": "acme.com", + "id": "org_0aBcDeFgHiJkLmNoPqRsTu", + "industry": "fintech", + "name": "Example Name", + "onboarding_solution_lookup_key": "string", + "onboarding_track": "vendor", + "owned_products": [ + "agent-rooms" + ], + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "status": "active", + "updated_at": "2024-01-01T00:00:00Z", + "vendor": { + "id": "org_0aBcDeFgHiJkLmNoPqRsTu", + "logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name" + }, + "website": "https://example.com" + } + ], + "items": { + "description": "A full organization object returned on org management endpoints. Includes identity, branding, and onboarding metadata for the authenticated caller's organization.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "domain": "acme.com", + "id": "org_0aBcDeFgHiJkLmNoPqRsTu", + "industry": "fintech", + "name": "Example Name", + "onboarding_solution_lookup_key": "string", + "onboarding_track": "vendor", + "owned_products": [ + "agent-rooms" + ], + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "status": "active", + "updated_at": "2024-01-01T00:00:00Z", + "vendor": { + "id": "org_0aBcDeFgHiJkLmNoPqRsTu", + "logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name" + }, + "website": "https://example.com" + }, + "properties": { + "created_at": { + "description": "When this organization was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short human-readable description of the organization. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "domain": { + "description": "Primary domain associated with the organization, e.g. `\"acme.com\"`. `null` if not configured.", + "example": "acme.com", + "type": "string" + }, + "id": { + "description": "Organization ID (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "industry": { + "description": "Industry category the organization belongs to, e.g. `\"fintech\"` or `\"healthcare\"`. `null` if not set.", + "example": "fintech", + "type": "string" + }, + "name": { + "description": "Display name of the organization. `null` if the org has not set a name.", + "example": "Example Name", + "type": "string" + }, + "onboarding_solution_lookup_key": { + "description": "Lookup key (`sol-...`) of the Solution that drove this org's customer onboarding, stamped when the org was first linked into a vendor's network via an explore-install. `null` for vendor-track orgs and invite-driven customers. The onboarding UI reads the referenced Solution's `metadata.onboarding` block to tailor the customer checklist.", + "example": "string", + "type": "string" + }, + "onboarding_track": { + "description": "The new-user experience track this org first completed. `\"vendor\"` for orgs that onboarded as service providers; `\"customer\"` for orgs that onboarded as buyers. `null` if onboarding was not tracked.", + "example": "vendor", + "type": "string" + }, + "owned_products": { + "description": "Catalog product IDs this organization's plan includes, e.g. `[\"agent-rooms\"]`, `[\"agent-solutions\"]`, `[\"agent-customer-management\"]`. Empty when the org has no plan. Clients use this to show which products the org actually has rather than inferring from feature flags. Derived from the org's plan, so it reflects what is currently paid for.", + "example": [ + "agent-rooms" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "sandbox": { + "description": "ID of the sandbox environment scoped to this organization (`snd_...`). `null` for organizations in production mode.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "slug": { + "description": "URL-safe identifier for the organization, used in vanity URLs and slug-based lookups.", + "example": "example-slug", + "type": "string" + }, + "status": { + "description": "Current lifecycle status of the organization, e.g. `\"active\"` or `\"suspended\"`. `null` if the status has not been set.", + "example": "active", + "type": "string" + }, + "updated_at": { + "description": "When this organization was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "vendor": { + "description": "Branding of the solution vendor whose network this organization belongs to — the vendor of the oldest active vendor relationship. Only present for organizations on the `\"customer\"` onboarding track; `null` for vendor-track organizations (including vendors that later joined another vendor's network) and for customers with no active vendor link. Clients use it to co-brand the workspace (\"ArchAgents by Acme\").", + "example": { + "id": "org_0aBcDeFgHiJkLmNoPqRsTu", + "logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "name": "Example Name" + }, + "properties": { + "id": { + "description": "Organization ID of the vendor (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "logo": { + "description": "Logo of the vendor organization. The `url` is a stable, non-expiring capability URL served by the platform (the same mechanism as catalog `org_logo` fields), safe to hold in caches; `refresh_url` is `null`. `null` when the vendor has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "description": "Display name of the vendor organization. `null` if the vendor has not set a name.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "website": { + "description": "Public website URL for the organization. `null` if not set.", + "example": "https://example.com", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + } + }, + "summary": "List organizations for a user", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/users/{user}/profile": { + "put": { + "description": "Updates one or more profile fields for the authenticated user. All\nfields are optional; omit any you do not want to change.\n\nWhen `profile_picture` is supplied, the image is uploaded and replaces\nthe existing picture. The previous picture is deleted after the new one\nis stored. Image upload failures return 422 without modifying other\nprofile fields.\n", + "operationId": "put_api_v1_users__user_profile", + "parameters": [ + { + "description": "User ID (`usr_...`) or `\"me\"` for the authenticated user.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "alias": "string", + "full_name": "Example Name", + "metadata": { + "key": "value" + }, + "profile_picture": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + } + }, + "properties": { + "alias": { + "description": "Short display alias shown in place of the full name in compact UI contexts.", + "example": "string", + "type": "string" + }, + "full_name": { + "description": "Updated display name for the user.", + "example": "Example Name", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata to associate with the user. Existing keys are merged; pass `null` for a key to remove it.", + "example": { + "key": "value" + }, + "type": "object" + }, + "profile_picture": { + "description": "New profile picture to upload as a base64-encoded image. Replaces any existing picture.", + "example": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "properties": { + "data": { + "description": "Base64-encoded binary content of the image file.", + "example": "string", + "type": "string" + }, + "filename": { + "description": "Original filename of the image, used for storage metadata.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`.", + "example": "application/json", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "description": "The user object with updated profile fields." + }, + "401": { + "description": "Unauthorized" + }, + "422": { + "description": "Validation error" + } + }, + "summary": "Update the current user's profile", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/users/{user}/tasks": { + "get": { + "description": "Returns tasks owned by the specified user or team. You can narrow results using the\noptional filters below. By default results are returned in reverse chronological\norder (most recently created first); use `sort` and `order` to sort by due date or\npriority instead.\n\nUser-authenticated callers may list their personal tasks or tasks for teams they\nhave joined. Privileged callers provide the owner in the route; the owner's\norganization is implied by that principal. An explicit `org` is optional and,\nwhen set, must match the owner's organization.\n", + "operationId": "get_api_v1_users__user_tasks", + "parameters": [ + { + "description": "Team ID (`tem_...`). Only tasks belonging to this team are returned.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) for user-scoped tasks.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Optional organization (`org_...`) for developer and server-to-server calls. When omitted, the org is taken from the owner principal (team, user, or agent). When set, it must match that principal's org; pass null for an owner outside an organization.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter tasks by status. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`. Omit to return tasks in all statuses.", + "example": "string", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter tasks assigned to a specific user. Provide the user's public ID (`usr_...`).", + "example": "string", + "in": "query", + "name": "owner_user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter tasks assigned to a specific agent. Provide the agent's public ID (`agi_...`).", + "example": "string", + "in": "query", + "name": "owner_agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter tasks by priority, from 0 (highest) to 4 (lowest).", + "example": 1, + "in": "query", + "name": "priority", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Return only tasks carrying this tag (matched against the canonical lowercase form).", + "example": "string", + "in": "query", + "name": "tag", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return only subtasks of the given task (`tsk_...`), or pass `none` to return only top-level tasks.", + "example": "string", + "in": "query", + "name": "parent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Restrict results to tasks whose name or description contains this string.", + "example": "string", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Sort key. One of `\"created\"` (default — most recently created first), `\"due_date\"` (soonest due first; tasks without a due date always sort last), or `\"priority\"` (most urgent first). Ties break by most recently created.", + "example": "string", + "in": "query", + "name": "sort", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Sort direction, `\"asc\"` or `\"desc\"`. Defaults to `\"desc\"` for `created` and `\"asc\"` for `due_date` and `priority`.", + "example": "string", + "in": "query", + "name": "order", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return only tasks with a due date strictly before this ISO 8601 datetime (`2026-08-01T00:00:00Z`) or date (`2026-08-01`, meaning midnight UTC). Tasks without a due date are excluded.", + "example": "string", + "in": "query", + "name": "due_before", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return only tasks with a due date strictly after this ISO 8601 datetime or date. Tasks without a due date are excluded.", + "example": "string", + "in": "query", + "name": "due_after", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "When `true`, return only overdue tasks: a due date before the current UTC day and a status other than `\"done\"`. A task due today is not overdue.", + "example": true, + "in": "query", + "name": "overdue", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "When true, return only open tasks with no unfinished blockers and no active session lease. This is a projection snapshot; claim a lease before starting work.", + "example": true, + "in": "query", + "name": "ready", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Maximum number of tasks to return. Capped at 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the previous page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Filtered list of tasks for the owner.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "data": { + "description": "Array of task objects matching the requested filters.", + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A task representing a unit of work, optionally assignable to a user or agent.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "blocked_by_count": { + "description": "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind.", + "example": 1, + "type": "integer" + }, + "closed_at": { + "description": "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "comments_count": { + "description": "Total number of comments posted on this task.", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the task was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by_actor": { + "description": "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "created_by_agent": { + "description": "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_by_user": { + "description": "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "current_lease": { + "description": "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "nullable": true, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the coding session.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the coding session that holds the lease.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "session_name", + "harness", + "expires_at" + ], + "type": "object" + }, + "description": { + "description": "Long-form description or notes for the task. `null` if no description has been provided.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Task ID (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_blocked": { + "description": "`true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read.", + "example": true, + "type": "boolean" + }, + "links": { + "description": "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title of the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_actor": { + "description": "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "owner_agent": { + "description": "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_user": { + "description": "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level.", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "priority": { + "description": "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set.", + "example": 2, + "type": "integer" + }, + "sandbox": { + "description": "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`.", + "example": "open", + "type": "string" + }, + "subtasks_count": { + "description": "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.", + "example": 1, + "type": "integer" + }, + "tags": { + "description": "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the task was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task owner not found" + }, + "422": { + "description": "Invalid explicit owner or organization context" + } + }, + "summary": "List an owner's tasks", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new task owned by the specified user or team and returns the full\ntask object. User-authenticated calls are attributed to the authenticated\nuser or agent. App-scoped developer and server-to-server callers must provide\nthe task's explicit `org` scope and an explicit `user` or `agent` actor for\nteam tasks; a user-owned task reuses the user in the route unless an explicit\nagent is supplied. Every referenced principal is validated against the app,\nowner, and team membership before creation.\n", + "operationId": "post_api_v1_users__user_tasks", + "parameters": [ + { + "description": "User ID (`usr_...`). On a user route this is the task owner and creator; on a team route it is the explicit acting user for a developer or server-to-server call.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "agent": "string", + "org": "string", + "task": { + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "owner_agent": "string", + "owner_user": "string", + "parent": "tsk_01j3k5m7n9p2r4s6t8v0w1x2", + "priority": 2, + "status": "open", + "tags": [ + "backend", + "q3-launch" + ], + "thread": "thr_01j3k5m7n9p2r4s6t8v0w1x2" + }, + "team": "string" + }, + "properties": { + "agent": { + "description": "Explicit acting agent (`agi_...`) for a developer or server-to-server call. Mutually exclusive with an acting `user`; the agent must belong to the task owner.", + "example": "string", + "type": "string" + }, + "org": { + "description": "Explicit organization (`org_...`) for developer and server-to-server calls. Pass null when the owner is not organization-scoped. The value must match the selected user or team.", + "example": "string", + "type": "string" + }, + "task": { + "description": "Attributes for the task to create. `name` is required; all other fields are optional.", + "example": { + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "owner_agent": "string", + "owner_user": "string", + "parent": "tsk_01j3k5m7n9p2r4s6t8v0w1x2", + "priority": 2, + "status": "open", + "tags": [ + "backend", + "q3-launch" + ], + "thread": "thr_01j3k5m7n9p2r4s6t8v0w1x2" + }, + "properties": { + "description": { + "description": "Optional long-form description or notes for the task. Supports plain text.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). Omit to create the task without a due date.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "links": { + "description": "Arbitrary key-value map of named URLs or references associated with the task (e.g. external ticket links).", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map for storing application-specific data alongside the task. Omit to create the task with no metadata.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title for the task.", + "example": "Example Name", + "type": "string" + }, + "owner_agent": { + "description": "ID of the agent to assign as owner (`agi_...`). Mutually exclusive with `owner_user`; omit to leave the task unassigned.", + "example": "string", + "type": "string" + }, + "owner_user": { + "description": "ID of the user to assign as owner (`usr_...`). Mutually exclusive with `owner_agent`; omit to leave the task unassigned.", + "example": "string", + "type": "string" + }, + "parent": { + "description": "Create this task as a subtask of an existing top-level task (`tsk_...`). Subtasks nest exactly one level.", + "example": "tsk_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "priority": { + "description": "Priority level from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when omitted.", + "example": 2, + "type": "integer" + }, + "status": { + "description": "Initial status for the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`. Defaults to `\"open\"` when omitted.", + "example": "open", + "type": "string" + }, + "tags": { + "description": "Labels for grouping and filtering (max 20, each up to 40 characters). Stored canonically: lowercase, trimmed, de-duplicated.", + "example": [ + "backend", + "q3-launch" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "thread": { + "description": "Bind the task to a thread (`thr_...`) owned by the same team or user as the task. A bound task appears in that thread's task scope, exactly like a task filed from inside the conversation. Omit for a task not tied to a conversation.", + "example": "thr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "team": { + "description": "Team ID (`tem_...`). The task will be owned by this team.", + "example": "string", + "type": "string" + } + }, + "required": [ + "task" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Task" + } + } + }, + "description": "The newly created task." + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task owner not found" + }, + "422": { + "description": "Validation error" + } + }, + "summary": "Create a task for an owner", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/users/{user}/tasks/blocker_cycles": { + "get": { + "description": "Runs an on-demand diagnostic over unfinished tasks owned by the specified\nteam or user and returns a forward cursor-paginated page of complete cyclic\nblocker components. Detection is bounded to owners with at most 100\nunfinished tasks. This endpoint is read-only: cycles do not prevent task\nupdates, lease acquisition, or completion.\n", + "operationId": "get_api_v1_users__user_tasks_blocker_cycles", + "parameters": [ + { + "description": "Team ID (`tem_...`) owning the tasks.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) owning the tasks.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Optional organization context for privileged callers.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum cycle components to return. Defaults to 50; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the preceding page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "On-demand task blocker cycle diagnostics.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "tasks": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ] + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "data": { + "example": [ + { + "tasks": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ] + } + ], + "items": { + "description": "A strongly connected component of unfinished task blocker edges.", + "example": { + "tasks": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ] + }, + "properties": { + "tasks": { + "description": "Every unfinished task in this cyclic blocker component.", + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A task representing a unit of work, optionally assignable to a user or agent.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "blocked_by_count": { + "description": "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind.", + "example": 1, + "type": "integer" + }, + "closed_at": { + "description": "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "comments_count": { + "description": "Total number of comments posted on this task.", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the task was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by_actor": { + "description": "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "created_by_agent": { + "description": "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_by_user": { + "description": "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "current_lease": { + "description": "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "nullable": true, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the coding session.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the coding session that holds the lease.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "session_name", + "harness", + "expires_at" + ], + "type": "object" + }, + "description": { + "description": "Long-form description or notes for the task. `null` if no description has been provided.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Task ID (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_blocked": { + "description": "`true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read.", + "example": true, + "type": "boolean" + }, + "links": { + "description": "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title of the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_actor": { + "description": "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "owner_agent": { + "description": "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_user": { + "description": "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level.", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "priority": { + "description": "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set.", + "example": 2, + "type": "integer" + }, + "sandbox": { + "description": "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`.", + "example": "open", + "type": "string" + }, + "subtasks_count": { + "description": "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.", + "example": 1, + "type": "integer" + }, + "tags": { + "description": "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the task was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "tasks" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task owner not found" + }, + "422": { + "description": "Invalid owner context or diagnostic limit" + } + }, + "summary": "List task blocker cycles", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/users/{user}/tasks/ready": { + "get": { + "description": "Returns open tasks with no unfinished blockers and no active session lease.\nReadiness is calculated by the server from the current task projection. It is\na snapshot, not a reservation; claim a task lease before starting work.\n\nPass `explain=true` to include every open task with a stable readiness reason.\n", + "operationId": "get_api_v1_users__user_tasks_ready", + "parameters": [ + { + "description": "Team ID (`tem_...`) owning the tasks.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) owning the tasks.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Optional organization context for privileged callers.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Include blocked and actively leased open tasks with exclusion reasons.", + "example": true, + "in": "query", + "name": "explain", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Only include tasks assigned to the authenticated user.", + "example": true, + "in": "query", + "name": "assigned_to_me", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Maximum number of readiness entries to return. Capped at 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the previous page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Cursor-paginated readiness results for the owner.", + "example": { + "after_cursor": "string", + "authoritative": true, + "before_cursor": "string", + "data": [ + { + "readiness": "ready", + "reason": "open_blockers", + "task": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "authoritative": { + "description": "Always false because projections can lag writes and a later claim can race this read.", + "example": true, + "type": "boolean" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "data": { + "example": [ + { + "readiness": "ready", + "reason": "open_blockers", + "task": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + } + ], + "items": { + "description": "A task plus the server-calculated reason it is or is not ready.", + "example": { + "readiness": "ready", + "reason": "open_blockers", + "task": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + }, + "properties": { + "readiness": { + "description": "One of `ready`, `blocked`, or `leased`.", + "enum": [ + "ready", + "blocked", + "leased" + ], + "example": "ready", + "type": "string" + }, + "reason": { + "description": "Stable exclusion reason: `open_blockers` or `active_lease`; omitted when ready.", + "enum": [ + "open_blockers", + "active_lease" + ], + "example": "open_blockers", + "nullable": true, + "type": "string" + }, + "task": { + "description": "The task evaluated for readiness.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "blocked_by_count": { + "description": "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind.", + "example": 1, + "type": "integer" + }, + "closed_at": { + "description": "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "comments_count": { + "description": "Total number of comments posted on this task.", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the task was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by_actor": { + "description": "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "created_by_agent": { + "description": "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_by_user": { + "description": "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "current_lease": { + "description": "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "nullable": true, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the coding session.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the coding session that holds the lease.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "session_name", + "harness", + "expires_at" + ], + "type": "object" + }, + "description": { + "description": "Long-form description or notes for the task. `null` if no description has been provided.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Task ID (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_blocked": { + "description": "`true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read.", + "example": true, + "type": "boolean" + }, + "links": { + "description": "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title of the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_actor": { + "description": "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "owner_agent": { + "description": "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_user": { + "description": "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level.", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "priority": { + "description": "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set.", + "example": 2, + "type": "integer" + }, + "sandbox": { + "description": "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`.", + "example": "open", + "type": "string" + }, + "subtasks_count": { + "description": "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.", + "example": 1, + "type": "integer" + }, + "tags": { + "description": "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the task was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status" + ], + "type": "object" + } + }, + "required": [ + "task", + "readiness" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "data", + "authoritative", + "has_more" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task owner not found" + }, + "422": { + "description": "Invalid owner context or pagination cursor" + } + }, + "summary": "List an owner's ready tasks", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/users/{user}/tasks/search": { + "get": { + "description": "Performs a full-text search over tasks owned by the specified user or team and returns\nmatching results. Combine `q` with the optional filters to narrow the result set\nfurther. When no query is provided, the endpoint behaves like a filtered list.\n\nThe `query` field in the response echoes the effective search query.\nUser-authenticated callers may search their personal tasks or tasks for teams\nthey have joined. Privileged callers provide the owner in the route; the owner's\norganization is implied by that principal. An explicit `org` is optional and,\nwhen set, must match the owner's organization.\n", + "operationId": "get_api_v1_users__user_tasks_search", + "parameters": [ + { + "description": "Team ID (`tem_...`). Only tasks belonging to this team are searched.", + "example": "string", + "in": "query", + "name": "team", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "User ID (`usr_...`) whose tasks are searched.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Optional organization (`org_...`) for developer and server-to-server calls. When omitted, the org is taken from the owner principal (team, user, or agent). When set, it must match that principal's org; pass null for an owner outside an organization.", + "example": "string", + "in": "query", + "name": "org", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Full-text search query matched against task names and descriptions. Takes precedence over `query` when both are provided.", + "example": "string", + "in": "query", + "name": "q", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Alias for `q`. Use `q` when possible; this parameter exists for compatibility.", + "example": "string", + "in": "query", + "name": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter results by status. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`. Omit to include all statuses.", + "example": "string", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Restrict results to tasks assigned to the user with this public ID (`usr_...`).", + "example": "string", + "in": "query", + "name": "owner_user", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Restrict results to tasks assigned to the agent with this public ID (`agi_...`).", + "example": "string", + "in": "query", + "name": "owner_agent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter results by priority, from 0 (highest) to 4 (lowest).", + "example": 1, + "in": "query", + "name": "priority", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Return only tasks carrying this tag (matched against the canonical lowercase form).", + "example": "string", + "in": "query", + "name": "tag", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return only subtasks of the given task (`tsk_...`), or pass `none` to return only top-level tasks.", + "example": "string", + "in": "query", + "name": "parent", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of tasks to return. Capped at 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor returned by the previous page.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Search results for the owner's tasks.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "data": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "has_more": true, + "query": "string" + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "data": { + "description": "Array of task objects matching the query and filters.", + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A task representing a unit of work, optionally assignable to a user or agent.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "blocked_by_count": { + "description": "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind.", + "example": 1, + "type": "integer" + }, + "closed_at": { + "description": "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "comments_count": { + "description": "Total number of comments posted on this task.", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the task was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by_actor": { + "description": "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "created_by_agent": { + "description": "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_by_user": { + "description": "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "current_lease": { + "description": "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "nullable": true, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the coding session.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the coding session that holds the lease.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "session_name", + "harness", + "expires_at" + ], + "type": "object" + }, + "description": { + "description": "Long-form description or notes for the task. `null` if no description has been provided.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Task ID (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_blocked": { + "description": "`true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read.", + "example": true, + "type": "boolean" + }, + "links": { + "description": "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title of the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_actor": { + "description": "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "owner_agent": { + "description": "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_user": { + "description": "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level.", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "priority": { + "description": "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set.", + "example": 2, + "type": "integer" + }, + "sandbox": { + "description": "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`.", + "example": "open", + "type": "string" + }, + "subtasks_count": { + "description": "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.", + "example": 1, + "type": "integer" + }, + "tags": { + "description": "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the task was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "example": true, + "type": "boolean" + }, + "query": { + "example": "string", + "type": "string" + } + }, + "required": [ + "data", + "has_more", + "query" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Task owner not found" + }, + "422": { + "description": "Invalid explicit owner or organization context" + } + }, + "summary": "Search an owner's tasks", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/users/{user}/threads": { + "get": { + "description": "Returns all threads visible to the specified user. The authenticated caller must\nhave access to the target user's account; a 403 is returned otherwise.\n\nPass one or more `agent` IDs to narrow results to threads where at least one of\nthe listed agents is also a member — useful for displaying every thread a user\nshares with a particular agent. Pass one or more `filter` objects to narrow\nresults by thread metadata key/value pairs. Both narrowings may be combined in\na single request.\n\nResults are returned as a flat array; no cursor-based pagination is applied.\nThreads are ordered with default threads first, then by most recent activity\n(newest first), each carrying a `last_activity` timestamp.\n", + "operationId": "get_api_v1_users__user_threads", + "parameters": [ + { + "description": "User ID (`usr_...`) whose threads should be listed.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Array of agent user IDs (`usr_...`). When provided, only threads where at least one of the listed agents is also a member are returned. Omit or pass an empty array to return all threads regardless of agent membership.", + "example": [ + "string" + ], + "in": "query", + "name": "agent", + "required": false, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Array of metadata filter objects. Each filter matches threads whose `metadata` map contains the specified key/value pair. All filters must match (logical AND). Omit to return threads regardless of metadata.", + "example": [ + { + "key": "string", + "type": "metadata", + "value": "string" + } + ], + "in": "query", + "name": "filter", + "required": false, + "schema": { + "items": { + "description": "A simple key-value predicate for matching a top-level metadata field. Use MetadataQuery for compound boolean expressions.", + "example": { + "key": "string", + "type": "metadata", + "value": "string" + }, + "properties": { + "key": { + "description": "Top-level key of the metadata object to match against.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Filter discriminator. Must be `\"metadata\"` to identify this as a metadata filter.", + "example": "metadata", + "type": "string" + }, + "value": { + "description": "Expected value for the given `key`. Matched with strict equality against the stored metadata.", + "example": "string", + "type": "string" + } + }, + "required": [ + "type", + "key", + "value" + ], + "type": "object" + }, + "type": "array" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Listing of threads visible to the user.", + "example": { + "data": [ + { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + } + ] + }, + "properties": { + "data": { + "description": "Array of thread objects matching the requested filters and agent narrowings.", + "example": [ + { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + } + ], + "items": { + "description": "A chat thread, representing a conversation channel that can be owned by a user, team, or agent and may contain messages, participants, and AI agent activity.", + "example": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + }, + "properties": { + "agent_user": { + "description": "ID of the agent that owns this thread (`agt_...`). `null` for user-owned or team-owned threads.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the thread was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "creator": { + "description": "User who created this thread. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if the creator is unknown.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "oneOf": [ + { + "type": "string" + }, + { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + }, + "description": { + "description": "Optional description or purpose statement for the thread. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Thread ID (`thr_...`).", + "example": "string", + "type": "string" + }, + "is_channel": { + "description": "Whether this thread operates as a channel — a multi-member broadcast-style conversation.", + "example": true, + "type": "boolean" + }, + "is_default": { + "description": "Whether this is the default thread for its owner. Each user or team has at most one default thread.", + "example": true, + "type": "boolean" + }, + "is_transient": { + "description": "Whether this thread is ephemeral and may be deleted automatically after a period of inactivity or when its TTL expires.", + "example": true, + "type": "boolean" + }, + "is_unlisted": { + "description": "Whether this thread is hidden from public discovery. Unlisted threads are accessible only to direct participants.", + "example": true, + "type": "boolean" + }, + "key": { + "description": "Application-defined stable key that uniquely identifies the thread within its scope. Useful for idempotent creation. `null` if not set.", + "example": "string", + "type": "string" + }, + "kind": { + "description": "Thread subtype: `\"standard\"` for ordinary threads, `\"slack_mirror\"` for the membership-strict mirror of a Slack channel, `\"slashwork_mirror\"` for the membership-strict mirror of a Slashwork group. Read-only — derived server-side at creation, never accepted from params.", + "example": "string", + "type": "string" + }, + "last_activity": { + "description": "When the most recent message was posted in this thread, falling back to the thread's creation time if it has no messages. Always populated on thread list endpoints (which order by it, after default threads); `null` on endpoints that don't compute activity enrichment.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "last_message_preview": { + "description": "Single-line snippet of the most recent message's text content (first non-empty line, truncated to 140 characters). Populated on thread list endpoints alongside `last_activity`; `null` when the thread has no messages, the latest message has no text content (e.g. attachment-only), or the endpoint doesn't compute activity enrichment.", + "example": "Sounds good — I'll ship the fix tomorrow.", + "type": "string" + }, + "last_message_sender": { + "description": "Display name of the sender of the most recent message — the same message `last_message_preview` snippets. Populated on thread list endpoints; `null` when the thread has no messages or the endpoint doesn't compute activity enrichment.", + "example": "Alice Chen", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the thread. Shape is application-defined; `null` if no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "muted": { + "description": "Whether the authenticated user has muted notifications for this thread. `true` suppresses all notification delivery.", + "example": true, + "type": "boolean" + }, + "org": { + "description": "ID of the organization this thread belongs to (`org_...`). `null` for threads outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent_message": { + "description": "The message that spawned this thread as a sub-thread. `null` for top-level threads.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "example": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "items": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "example": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "items": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "example": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "items": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "example": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "items": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "participant": { + "description": "Array of participant user IDs (`usr_...`) who are members of this thread.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "participants": { + "description": "Expanded participant user objects for each member of this thread. Populated only when the association is loaded.", + "example": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "items": { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "participating_actor": { + "description": "Composite actor identifiers for all participants currently active in this thread. Present only when actor enrichment is requested.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "participating_agents": { + "description": "Expanded agent objects for all agents participating in this thread. Present only when agent enrichment is requested.", + "example": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "An AI agent that can be configured with tools, routines, and skills, and invoked to handle conversations or tasks.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints.", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "solution": { + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "role": { + "description": "The authenticated user's membership role in this thread, e.g. `\"owner\"`, `\"member\"`, or `\"viewer\"`. `null` if the user is not a member.", + "example": "member", + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this thread is scoped to (`dsb_...`). `null` for production threads.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "settings": { + "description": "Per-thread configuration settings controlling AI agent behavior for this thread.", + "example": { + "agent_enabled": true + }, + "properties": { + "agent_enabled": { + "description": "Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured.", + "example": true, + "type": "boolean" + } + }, + "type": "object" + }, + "slug": { + "description": "URL-safe slug for the thread, used in human-readable permalinks. `null` if not assigned.", + "example": "example-slug", + "type": "string" + }, + "sub_threads": { + "description": "Threads that are nested under this thread as replies to a parent message. Present only when sub-thread enrichment is requested.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "tags": { + "description": "Status tags on the thread (e.g. `\"blocked\"`, `\"needs-review\"`). Edited by any thread participant via the `/threads/:thread/tags` endpoints and filterable on the thread list endpoints. Empty array if none set.", + "example": [ + "blocked", + "needs-review" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this thread (`team_...`). `null` for user-owned or agent-owned threads.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "title": { + "description": "Human-readable name of the thread. `null` if no title has been set.", + "example": "Example Title", + "type": "string" + }, + "ttl": { + "description": "Time-to-live in seconds after which the thread may be automatically cleaned up. `null` if the thread does not expire.", + "example": 3600, + "type": "integer" + }, + "unread_count": { + "description": "Number of messages in this thread that the authenticated user has not yet read. Present only when read-state enrichment is requested.", + "example": 5, + "type": "integer" + }, + "updated_at": { + "description": "When the thread was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user who owns this thread (`usr_...`). `null` for team-owned or agent-owned threads.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "visibility": { + "description": "Who can read the thread: `team` for every owning-team member, `restricted` for team-readable threads with an explicit roster, or `private` for roster-only access.", + "enum": [ + "team", + "restricted", + "private" + ], + "example": "team", + "type": "string" + } + }, + "required": [ + "id", + "visibility" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "summary": "List threads for a user", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Creates a new thread owned by the specified user. The authenticated caller must\nhave access to the target user's account; a 403 is returned otherwise.\n\nAn automatic welcome message is sent into the thread upon creation unless\n`skip_welcome_message` is set to `true`. The thread is immediately visible to\nthe owning user and any members added at creation time.\n", + "operationId": "post_api_v1_users__user_threads", + "parameters": [ + { + "description": "User ID (`usr_...`) of the user who will own the new thread.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "skip_welcome_message": true, + "thread": { + "create_legacy_agent": true, + "description": "An example description.", + "is_unlisted": true, + "key": "string", + "members": [ + { + "id": "string", + "type": "user" + } + ], + "metadata": { + "key": "value" + }, + "muted": true, + "org_id": "string", + "profile_picture": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "title": "Example Title", + "visibility": "team" + } + }, + "properties": { + "skip_welcome_message": { + "description": "When `true`, suppresses the automatic welcome message that is otherwise sent into the thread on creation. Defaults to `false`.", + "example": true, + "type": "boolean" + }, + "thread": { + "description": "Attributes for the new thread. See ThreadCreateParams for the full set of accepted fields.", + "example": { + "create_legacy_agent": true, + "description": "An example description.", + "is_unlisted": true, + "key": "string", + "members": [ + { + "id": "string", + "type": "user" + } + ], + "metadata": { + "key": "value" + }, + "muted": true, + "org_id": "string", + "profile_picture": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "title": "Example Title", + "visibility": "team" + }, + "properties": { + "create_legacy_agent": { + "description": "When `true`, provisions a legacy chat agent alongside the thread. Only needed for integrations that depend on the pre-v2 agent model.", + "example": true, + "type": "boolean" + }, + "description": { + "description": "Optional longer description of the thread's purpose. `null` if not provided.", + "example": "An example description.", + "type": "string" + }, + "is_unlisted": { + "description": "When `true`, the thread is hidden from the default thread list and accessible only by direct link or ID.", + "example": true, + "type": "boolean" + }, + "key": { + "description": "Client-assigned unique key for idempotent creation or later lookup. Must be unique within the owning organization.", + "example": "string", + "type": "string" + }, + "members": { + "description": "Users and agents to add atomically when the thread is created. Each target must pass the same authorization rules as a post-creation member add. Slack mirror threads reject non-empty caller-supplied rosters because their membership is sync-owned.", + "example": [ + { + "id": "string", + "type": "user" + } + ], + "items": { + "description": "A user or agent to add atomically when the thread is created.", + "example": { + "id": "string", + "type": "user" + }, + "properties": { + "id": { + "description": "Public user (`usr_...`) or agent (`agt_...`) ID matching `type`.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Member kind. Use `user` for a user ID or `agent` for an agent ID.", + "enum": [ + "user", + "agent" + ], + "example": "user", + "type": "string" + } + }, + "required": [ + "type", + "id" + ], + "type": "object" + }, + "type": "array" + }, + "metadata": { + "description": "Arbitrary key-value pairs stored alongside the thread. Values must be strings or numbers.", + "example": { + "key": "value" + }, + "type": "object" + }, + "muted": { + "description": "When `true`, push and in-app notifications for this thread are suppressed for the creating user.", + "example": true, + "type": "boolean" + }, + "org_id": { + "description": "ID of the organization to create the thread under. Defaults to the authenticated user's primary organization when omitted.", + "example": "string", + "type": "string" + }, + "profile_picture": { + "description": "Optional profile image for the thread, provided as a base64-encoded payload.", + "example": { + "data": "string", + "filename": "string", + "mime_type": "application/json" + }, + "properties": { + "data": { + "description": "Base64-encoded image bytes.", + "example": "string", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded image, used for display and content-type inference.", + "example": "string", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`.", + "example": "application/json", + "type": "string" + } + }, + "type": "object" + }, + "settings": { + "description": "Configuration overrides for the thread, such as AI model selection and context window settings.", + "example": { + "agent_enabled": true + }, + "properties": { + "agent_enabled": { + "description": "Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured.", + "example": true, + "type": "boolean" + } + }, + "type": "object" + }, + "slug": { + "description": "Optional URL-safe identifier. Derived from the title when omitted and unique within the thread owner.", + "example": "example-slug", + "type": "string" + }, + "title": { + "description": "Display name for the thread. `null` if omitted, which causes the thread to be untitled.", + "example": "Example Title", + "type": "string" + }, + "visibility": { + "description": "Thread visibility. A team-owned thread with members must explicitly use `restricted` or `private`. User- and agent-owned threads with members default to `private` and reject every other value.", + "enum": [ + "team", + "restricted", + "private" + ], + "example": "team", + "type": "string" + } + }, + "type": "object" + } + }, + "required": [ + "thread" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Thread" + } + } + }, + "description": "The newly created thread object." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "422": { + "description": "Validation failed" + } + }, + "summary": "Create a thread for a user", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/users/{user}/tokens": { + "get": { + "description": "Returns all access tokens associated with the authenticated user, including\nactive and revoked tokens. Tokens are returned without their raw JWT values\n— the plaintext JWT is only available at creation time.\n\nThe caller must be the user identified by `user` and must present a\nfirst-party session (or a `full_access` access token).\n", + "operationId": "get_api_v1_users__user_tokens", + "parameters": [ + { + "description": "User ID (`usr_...`) or `me` for the authenticated user.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Collection of access tokens for the user.", + "example": { + "data": [ + { + "created_at": "2024-01-01T00:00:00Z", + "expires_at": "2024-01-01T00:00:00Z", + "id": "sat_0aBcDeFgHiJkLmNoPqRsTu", + "last_used_at": "2024-01-01T00:00:00Z", + "name": "Example Name", + "revoked_at": "2024-01-01T00:00:00Z", + "scopes": "string", + "token": "string" + } + ] + }, + "properties": { + "data": { + "description": "Array of access token objects. Raw JWT values are not included.", + "example": [ + { + "created_at": "2024-01-01T00:00:00Z", + "expires_at": "2024-01-01T00:00:00Z", + "id": "sat_0aBcDeFgHiJkLmNoPqRsTu", + "last_used_at": "2024-01-01T00:00:00Z", + "name": "Example Name", + "revoked_at": "2024-01-01T00:00:00Z", + "scopes": "string", + "token": "string" + } + ], + "items": { + "description": "A long-lived API credential associated with a system account, used to authenticate server-to-server requests.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "expires_at": "2024-01-01T00:00:00Z", + "id": "sat_0aBcDeFgHiJkLmNoPqRsTu", + "last_used_at": "2024-01-01T00:00:00Z", + "name": "Example Name", + "revoked_at": "2024-01-01T00:00:00Z", + "scopes": "string", + "token": "string" + }, + "properties": { + "created_at": { + "description": "When this token was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "expires_at": { + "description": "When the token expires. `null` on legacy rows that predate stored expiry.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Token ID (`sat_...`).", + "example": "sat_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "last_used_at": { + "description": "When this token was last used to authenticate a request. `null` if the token has never been used.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "name": { + "description": "Human-readable label assigned to this token at creation time.", + "example": "Example Name", + "type": "string" + }, + "revoked_at": { + "description": "When this token was revoked. `null` if the token is still active.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "scopes": { + "description": "Space-separated OAuth scopes stamped on the token. `null` on legacy rows; treat as `full_access`.", + "example": "string", + "type": "string" + }, + "token": { + "description": "Raw bearer token string. Present only in the response to the create request; never returned again after that.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "summary": "List personal access tokens", + "x-auth": [ + "publishable_key", + "bearer" + ] + }, + "post": { + "description": "Issues a new long-lived access token for the authenticated user. The raw\nJWT is returned in the `token` field of the response exactly once and\ncannot be retrieved again — store it securely immediately after creation.\n\n`scopes` is optional. When omitted the token receives `full_access`.\nKnown catalog scopes (for example `profile`) restrict the token through\nthe same `ScopeGuard` used by OAuth.\n\n`expires_in_days` is optional and must be one of `7`, `30`, `60`, `90`,\nor `365`. When omitted the token lasts 30 days. Each user may hold at\nmost 50 active tokens; exceeding that limit returns 429.\n\nThe caller must be the user identified by `user` and must present a\nfirst-party session (or a `full_access` access token). A restricted\naccess token cannot mint another token.\n", + "operationId": "post_api_v1_users__user_tokens", + "parameters": [ + { + "description": "User ID (`usr_...`) or `me` for the authenticated user.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "expires_in_days": 1, + "name": "Example Name", + "scopes": [ + "string" + ] + }, + "properties": { + "expires_in_days": { + "description": "Lifetime in days. One of `7`, `30`, `60`, `90`, or `365`. Defaults to `30`.", + "example": 1, + "type": "integer" + }, + "name": { + "description": "Human-readable label for the token (e.g. `\"Codex MCP\"`). Stored as metadata only.", + "example": "Example Name", + "type": "string" + }, + "scopes": { + "description": "Optional OAuth scopes to stamp on the token. Omit for `full_access`.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SystemAccessToken" + } + } + }, + "description": "The newly created access token. The `token` field contains the raw JWT and is present only in this response — it is not stored and cannot be retrieved later." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "422": { + "description": "Invalid scopes, expiration, or user is a system user" + }, + "429": { + "description": "Token limit reached" + } + }, + "summary": "Create a personal access token", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/users/{user}/tokens/{token}": { + "delete": { + "description": "Permanently revokes the specified access token belonging to the\nauthenticated user. Once revoked, the token is immediately rejected by\nall API endpoints and cannot be reinstated. The token record is retained\nand returned in the response with `revoked_at` populated.\n\nThe caller must be the user identified by `user` and must present a\nfirst-party session (or a `full_access` access token). Returns 404 if\nthe token does not exist or does not belong to the caller.\n", + "operationId": "delete_api_v1_users__user_tokens__token", + "parameters": [ + { + "description": "User ID (`usr_...`) or `me` for the authenticated user.", + "example": "string", + "in": "path", + "name": "user", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Access token ID (`sat_...`). Must belong to the authenticated user.", + "example": "string", + "in": "path", + "name": "token", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SystemAccessToken" + } + } + }, + "description": "The revoked access token. The `revoked_at` field is populated with the time of revocation." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Token not found" + } + }, + "summary": "Revoke a personal access token", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/work_items": { + "get": { + "description": "Lists queued, claimed, and running external work yielded by durable workflows.\nThe top-level collection includes work for every agent the viewer can execute;\nthe agent-nested collection limits results to that agent. This discovery\nresponse never includes lease tokens. Use the agent claim endpoint to acquire\nnew work or resume a saved lease.\n", + "operationId": "get_api_v1_work_items", + "parameters": [ + { + "description": "Optional durable execution ID filter.", + "example": "string", + "in": "query", + "name": "execution", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum work items per page. Defaults to 50; maximum is 100.", + "example": 1, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "description": "Opaque cursor for the next page of older queued work.", + "example": "string", + "in": "query", + "name": "after_cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkflowWorkItemList" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Invalid cursor" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "Invalid parameters" + } + }, + "summary": "List active workflow work available to the viewer", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/work_items/{work_item}/fail": { + "post": { + "description": "Atomically records command failure, marks the work item failed, and either\nwakes the workflow at the node's error edge or fails the owning run when no\nerror edge exists. Retrying the same lease and error is idempotent; a\ndifferent terminal payload conflicts.\n", + "operationId": "post_api_v1_work_items__work_item_fail", + "parameters": [ + { + "description": "Claimed or running work item ID.", + "example": "string", + "in": "path", + "name": "work_item", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "error": {}, + "lease_owner": "string" + }, + "properties": { + "error": { + "description": "JSON-serializable failure returned by the worker.", + "example": {}, + "type": "object" + }, + "lease_owner": { + "description": "Saved lease token.", + "example": "string", + "type": "string" + } + }, + "required": [ + "lease_owner", + "error" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No content" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Agent not found; Resource not found" + }, + "409": { + "description": "Conflict" + }, + "422": { + "description": "Invalid parameters; Validation failed" + } + }, + "summary": "Fail workflow work and route its durable execution", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/work_items/{work_item}/heartbeat": { + "post": { + "operationId": "post_api_v1_work_items__work_item_heartbeat", + "parameters": [ + { + "description": "Claimed or running work item ID.", + "example": "string", + "in": "path", + "name": "work_item", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "lease_owner": "string", + "lease_seconds": 1 + }, + "properties": { + "lease_owner": { + "description": "Saved lease token.", + "example": "string", + "type": "string" + }, + "lease_seconds": { + "description": "Replacement lease duration from 15 through 3600 seconds. Defaults to 300.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "lease_owner" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No content" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Agent not found; Resource not found" + }, + "409": { + "description": "Conflict" + }, + "422": { + "description": "Invalid parameters; Validation failed" + } + }, + "summary": "Extend a workflow work item lease", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/work_items/{work_item}/start": { + "post": { + "operationId": "post_api_v1_work_items__work_item_start", + "parameters": [ + { + "description": "Claimed work item ID.", + "example": "string", + "in": "path", + "name": "work_item", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "lease_owner": "string" + }, + "properties": { + "lease_owner": { + "description": "Saved lease token.", + "example": "string", + "type": "string" + } + }, + "required": [ + "lease_owner" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No content" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Agent not found; Resource not found" + }, + "409": { + "description": "Conflict" + }, + "422": { + "description": "Invalid parameters; Validation failed" + } + }, + "summary": "Mark claimed workflow work as running", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/api/v1/work_items/{work_item}/submit": { + "post": { + "description": "Atomically records the command completion, marks the work item succeeded,\nadvances the journal sequence, and enqueues the owning workflow continuation.\nRetrying the same lease and result is idempotent; a different result conflicts.\n", + "operationId": "post_api_v1_work_items__work_item_submit", + "parameters": [ + { + "description": "Claimed or running work item ID.", + "example": "string", + "in": "path", + "name": "work_item", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "lease_owner": "string", + "result": {} + }, + "properties": { + "lease_owner": { + "description": "Saved lease token.", + "example": "string", + "type": "string" + }, + "result": { + "description": "JSON-serializable output returned to the workflow.", + "example": {}, + "type": "object" + } + }, + "required": [ + "lease_owner", + "result" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No content" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "App-scoped token required. Use a token scoped to the target app.; Forbidden" + }, + "404": { + "description": "Agent not found; Resource not found" + }, + "409": { + "description": "Conflict" + }, + "422": { + "description": "Invalid parameters; Validation failed" + } + }, + "summary": "Submit workflow work output and wake its durable execution", + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, + "/oauth/device/approve": { + "post": { + "description": "Grants the pending device authorization identified by `user_code`, completing\nthe OAuth Device Authorization flow on behalf of the authenticated user. Once\napproved, the device can exchange the `device_code` for an access token.\n\nRequires a valid user session — the request must be authenticated as an end\nuser, not a machine client. The `user_code` must belong to a pending (not\nexpired, not already approved or denied) authorization associated with the\ncalling app.\n\nIf the requested scopes include a `thread`-scoped permission, you must supply\nthe `thread` parameter; omitting it returns a 400 with `error: \"invalid_scope\"`.\n", + "operationId": "post_oauth_device_approve", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "thread": "string", + "user_code": "string" + }, + "properties": { + "thread": { + "description": "Thread ID (`thr_...`) to bind to the authorization. Required when the requested scopes include a thread-scoped permission.", + "example": "string", + "type": "string" + }, + "user_code": { + "description": "User-facing verification code shown on the device. Identifies the pending authorization to approve.", + "example": "string", + "type": "string" + } + }, + "required": [ + "user_code" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeviceAuthorizationStatusResponse" + } + } + }, + "description": "Confirmation that the device authorization was approved. The `status` field will be `\"approved\"`." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + } + }, + "summary": "Approve a device authorization request" + } + }, + "/oauth/device/authorization": { + "get": { + "description": "Returns the client name, requested scopes, and expiration for a pending\ndevice authorization owned by the calling app. The caller must be an\nauthenticated user. This endpoint never approves the request.\n", + "operationId": "get_oauth_device_authorization", + "parameters": [ + { + "description": "User-facing device authorization code.", + "example": "string", + "in": "query", + "name": "code", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeviceAuthorizationDetailsResponse" + } + } + }, + "description": "Successful response" + }, + "400": { + "description": "Invalid or expired code" + }, + "401": { + "description": "Unauthorized" + } + }, + "summary": "Inspect a pending device authorization" + } + }, + "/oauth/device/authorize": { + "post": { + "description": "Starts the OAuth 2.0 Device Authorization flow for a device that cannot\nperform browser-based redirects. Returns a `device_code` (used by the device\nto poll for a token) and a `user_code` (shown to the user to enter at the\n`verification_uri`).\n\nThis endpoint requires a publishable API key; secret keys are rejected with\na 403. Third-party OAuth must be enabled on the app; if it is not, the\nresponse returns `error: \"third_party_oauth_not_enabled\"` with a 403.\n\nThe endpoint is rate-limited to 10 requests per IP per minute. Excess\nrequests receive a 429 response. The returned codes expire after\n`expires_in` seconds; once expired, a new authorization request must be\ninitiated.\n", + "operationId": "post_oauth_device_authorize", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "client": "string", + "scope": "string" + }, + "properties": { + "client": { + "description": "OAuth client ID (`cli_...`) identifying the application requesting authorization.", + "example": "string", + "type": "string" + }, + "scope": { + "description": "Space-separated list of OAuth scopes to request, e.g. `\"read write\"`. Omit to request only the default scopes configured for the client.", + "example": "string", + "type": "string" + } + }, + "required": [ + "client" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeviceAuthorizationResponse" + } + } + }, + "description": "Device authorization codes and polling parameters. Present the `user_code` to the user and direct them to `verification_uri`. Poll the token endpoint using `device_code` at the rate given by `interval`." + }, + "400": { + "description": "Bad request" + }, + "403": { + "description": "Forbidden" + }, + "429": { + "description": "Rate limited" + } + }, + "summary": "Initiate a device authorization request" + } + }, + "/oauth/device/deny": { + "post": { + "description": "Rejects the pending device authorization identified by `user_code`, preventing\nthe device from obtaining an access token. Once denied, the device will\nreceive an `access_denied` error on its next token poll.\n\nRequires a valid user session. The `user_code` must belong to a pending\nauthorization associated with the calling app. Attempting to deny an already\napproved, already denied, or expired authorization returns a 400.\n", + "operationId": "post_oauth_device_deny", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "user_code": "string" + }, + "properties": { + "user_code": { + "description": "User-facing verification code shown on the device. Identifies the pending authorization to deny.", + "example": "string", + "type": "string" + } + }, + "required": [ + "user_code" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeviceAuthorizationStatusResponse" + } + } + }, + "description": "Confirmation that the device authorization was denied. The `status` field will be `\"denied\"`." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + } + }, + "summary": "Deny a device authorization request" + } + }, + "/oauth/scopes": { + "get": { + "description": "Returns the complete set of OAuth scopes that the platform supports.\nUse this endpoint to discover which scopes are available before constructing\nan authorization request or rendering a consent UI.\n\nNo authentication is required. The response is the same for all callers.\n", + "operationId": "get_oauth_scopes", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "An object containing all available OAuth scope definitions.", + "example": { + "scopes": {} + }, + "properties": { + "scopes": { + "description": "Map of scope name to its definition object. Each key is a scope string (e.g. `\"threads:read\"`) and each value describes the scope's purpose and requirements.", + "example": {}, + "type": "object" + } + }, + "required": [ + "scopes" + ], + "type": "object" + } + } + }, + "description": "Successful response" + } + }, + "summary": "List available OAuth scopes" + } + }, + "/oauth/token": { + "post": { + "description": "Issues an access token and a refresh token in exchange for a valid grant.\nThree grant types are supported: `\"authorization_code\"`, `\"refresh_token\"`,\nand `\"urn:ietf:params:oauth:grant-type:device_code\"`.\n\nFor `\"authorization_code\"` grants, supply `code`, `client`, `redirect_uri`, and\noptionally `code_verifier` for PKCE flows. Each authorization code is single-use;\nconsuming it a second time returns `invalid_grant`.\n\nFor `\"refresh_token\"` grants, supply `refresh_token`. The endpoint rotates the\nrefresh token on every call and returns a fresh pair of tokens.\n\nFor device-code grants, supply `device_code` and `client`. Poll this endpoint\nafter receiving `authorization_pending` until the user approves or the code\nexpires. Slow down polling if you receive `slow_down`.\n\nThis endpoint is rate-limited to 20 requests per IP per 60 seconds. Exceeding\nthe limit returns HTTP 429 with `\"error\": \"too_many_requests\"`.\n", + "operationId": "post_oauth_token", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "example": { + "client": "string", + "code": "string", + "code_verifier": "string", + "device_code": "string", + "grant_type": "string", + "redirect_uri": "https://example.com", + "refresh_token": "string" + }, + "properties": { + "client": { + "description": "OAuth client ID identifying the application requesting tokens. Required for `\"authorization_code\"` and device-code grants.", + "example": "string", + "type": "string" + }, + "code": { + "description": "Single-use authorization code issued by the authorization endpoint. Required for `\"authorization_code\"` grants.", + "example": "string", + "type": "string" + }, + "code_verifier": { + "description": "PKCE code verifier corresponding to the `code_challenge` sent in the authorization request. Required when the authorization code was issued with a code challenge; omit otherwise.", + "example": "string", + "type": "string" + }, + "device_code": { + "description": "Device code received from the device authorization endpoint. Required for device-code grants.", + "example": "string", + "type": "string" + }, + "grant_type": { + "description": "The OAuth 2.0 grant type. One of `\"authorization_code\"`, `\"refresh_token\"`, or `\"urn:ietf:params:oauth:grant-type:device_code\"`.", + "example": "string", + "type": "string" + }, + "redirect_uri": { + "description": "Redirect URI that was used in the original authorization request. Must exactly match the URI on record for the client. Required for `\"authorization_code\"` grants.", + "example": "https://example.com", + "type": "string" + }, + "refresh_token": { + "description": "Refresh token received from a previous token response. Required for `\"refresh_token\"` grants. The token is rotated on each successful call.", + "example": "string", + "type": "string" + } + }, + "required": [ + "grant_type" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OAuthTokenResponse" + } + } + }, + "description": "Token pair issued for the authenticated user." + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "429": { + "description": "Rate limited" + } + }, + "summary": "Exchange a grant for OAuth tokens" + } + } + }, + "x-auth-schemes": { + "bearer": { + "description": "User JWT in Authorization header", + "scheme": "bearer", + "type": "http" + }, + "device_flow": { + "description": "Third-party device flow token — requires per-action opt-in", + "scheme": "bearer", + "type": "http", + "x-token-use": "third_party" + }, + "publishable_key": { + "description": "Publishable API key — identifies the app", + "in": "header", + "name": "x-archastro-api-key", + "prefix": "pk_", + "type": "api_key" + }, + "secret_key": { + "description": "Secret API key — full admin access, no user JWT required", + "in": "header", + "name": "x-archastro-api-key", + "prefix": "sk_", + "type": "api_key" + } + }, + "x-channel-auth": [ + "bearer" + ], + "x-channels": [ + { + "description": "Phoenix channel for real-time activity feed updates.\n\nClients join a topic scoped to an agent or org and receive\n`new_entry` events as feed entries are created.\n\n## Topics\n\n * `\"api:activity_feed:agent:{agent_user_id}\"` — entries for a specific agent\n * `\"api:activity_feed:org:{org_id}\"` — entries for an entire org/tenant\n", + "joins": [ + { + "description": "Join an agent-scoped activity feed", + "name": "join_agent", + "params": { + "example": { + "agent_id": "string" + }, + "properties": { + "agent_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "agent_id" + ], + "type": "object" + }, + "pattern": "api:activity_feed:agent:{agent_id}", + "returns": { + "type": "object" + } + }, + { + "description": "Join an org-scoped activity feed", + "name": "join_org", + "params": { + "example": { + "org_id": "string" + }, + "properties": { + "org_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "org_id" + ], + "type": "object" + }, + "pattern": "api:activity_feed:org:{org_id}", + "returns": { + "type": "object" + } + } + ], + "messages": [ + { + "description": "List activity feed entries with cursor-based pagination", + "event": "list_entries", + "params": { + "example": { + "after_cursor": "string", + "before_cursor": "string", + "kind": "string", + "level": "string", + "limit": 1 + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "kind": { + "example": "string", + "type": "string" + }, + "level": { + "example": "string", + "type": "string" + }, + "limit": { + "example": 1, + "type": "integer" + } + }, + "type": "object" + }, + "returns": { + "description": "A paginated list of activity feed entries returned by a feed query, with cursors for navigating backward and forward through results.", + "example": { + "after_cursor": "string", + "before_cursor": "string", + "entries": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "attachments": [ + {} + ], + "automation_run": "atr_0aBcDeFgHiJkLmNoPqRsTu", + "content": "The agent completed the task successfully.", + "correlation_id": "01234567-89ab-cdef-0123-456789abcdef", + "created_at": "2024-01-01T00:00:00Z", + "id": "afe_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_step", + "level": "info", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "routine_run": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "session_record": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "has_more": true + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor to pass as `after` to retrieve the next page of entries. `null` when this is the last page.", + "example": "string", + "type": "string" + }, + "before_cursor": { + "description": "Opaque cursor to pass as `before` to retrieve the previous page of entries. `null` when this is the first page.", + "example": "string", + "type": "string" + }, + "entries": { + "description": "Array of activity feed entry objects for the current page, ordered by time descending.", + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "attachments": [ + {} + ], + "automation_run": "atr_0aBcDeFgHiJkLmNoPqRsTu", + "content": "The agent completed the task successfully.", + "correlation_id": "01234567-89ab-cdef-0123-456789abcdef", + "created_at": "2024-01-01T00:00:00Z", + "id": "afe_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_step", + "level": "info", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "routine_run": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "session_record": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A single event record in an activity feed, capturing what happened, who caused it, and which resources were involved.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "attachments": [ + {} + ], + "automation_run": "atr_0aBcDeFgHiJkLmNoPqRsTu", + "content": "The agent completed the task successfully.", + "correlation_id": "01234567-89ab-cdef-0123-456789abcdef", + "created_at": "2024-01-01T00:00:00Z", + "id": "afe_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_step", + "level": "info", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "routine_run": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "string", + "session_record": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "The agent that produced this event. Returns an agent ID (`agi_...`) by default, or an expanded agent object when the association is loaded. `null` if no agent is associated.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "oneOf": [ + { + "type": "string" + }, + { + "description": "An AI agent that can be configured with tools, routines, and skills, and invoked to handle conversations or tasks.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints.", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "solution": { + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + }, + "app": { + "description": "ID of the application that produced this entry (`dap_...`). `null` if not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "attachments": { + "description": "Array of attachment objects associated with this entry. Each attachment has a `type` field (e.g. `\"file\"`, `\"task\"`, `\"artifact\"`) and type-specific additional fields. Empty array when there are no attachments.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "automation_run": { + "description": "ID of the automation run that produced this entry (`atr_...`). `null` if not produced by an automation run.", + "example": "atr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "content": { + "description": "A longer explanation of the event rendered as Markdown. `null` if no additional content is available.", + "example": "The agent completed the task successfully.", + "type": "string" + }, + "correlation_id": { + "description": "An opaque string used to group related entries together. Entries sharing the same `correlation_id` belong to a single logical operation. `null` if not correlated.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "created_at": { + "description": "When this activity feed entry was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Activity feed entry ID (`afe_...`).", + "example": "afe_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "The type of event this entry represents, e.g. `\"agent_step\"` or `\"tool_call\"`. Determines how `title`, `content`, and `attachments` should be interpreted.", + "example": "agent_step", + "type": "string" + }, + "level": { + "description": "Severity level of the event. One of `\"info\"`, `\"warning\"`, or `\"error\"`. `null` if no severity is set.", + "example": "info", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata stored on this entry. Returns an empty object when no metadata is set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization this entry belongs to (`org_...`). `null` if not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "routine_run": { + "description": "ID of the agent routine run that produced this entry (`arr_...`). `null` if not produced by a routine run.", + "example": "arr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "Identifier of the sandbox environment this entry was generated in. `null` in production contexts.", + "example": "string", + "type": "string" + }, + "session_record": { + "description": "ID of the agent session record this entry belongs to (`ase_...`). `null` if not part of an agent session.", + "example": "ase_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "team": { + "description": "ID of the team this entry is associated with (`tem_...`). `null` if not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this entry is associated with (`thr_...`). `null` if not linked to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "title": { + "description": "A one-line human-readable summary of the event. `null` if the entry has no title.", + "example": "Example Title", + "type": "string" + }, + "updated_at": { + "description": "When this activity feed entry was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "The user who triggered this event. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if no user is associated.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "oneOf": [ + { + "type": "string" + }, + { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "has_more": { + "description": "Whether additional entries exist beyond the current page. When `true`, use `after_cursor` to fetch the next page.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "entries", + "has_more" + ], + "type": "object" + } + } + ], + "name": "ApiActivityFeedChannel", + "pushes": [ + { + "description": null, + "event": "new_entry", + "payload": { + "example": { + "entry": {} + }, + "properties": { + "entry": { + "example": {}, + "type": "object" + } + }, + "type": "object" + } + } + ], + "x-auth": [ + "bearer" + ] + }, + { + "description": "Channel for real-time chat messaging.\n\nSupports team-scoped and user-scoped threads with keyed, transient, and direct\nthread access patterns.\n", + "joins": [ + { + "description": "Join a team-scoped thread by ID", + "name": "join_team_thread", + "params": { + "example": { + "after_cursor": "string", + "before_cursor": "string", + "include_metadata": true, + "limit": 1, + "team_id": "string", + "thread_id": "string" + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "include_metadata": { + "example": true, + "type": "boolean" + }, + "limit": { + "example": 1, + "type": "integer" + }, + "team_id": { + "example": "string", + "type": "string" + }, + "thread_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "team_id", + "thread_id" + ], + "type": "object" + }, + "pattern": "api:chat:team:{team_id}:thread:{thread_id}", + "returns": { + "type": "object" + } + }, + { + "description": "Join or create a team-scoped keyed thread", + "name": "join_team_keyed", + "params": { + "example": { + "after_cursor": "string", + "before_cursor": "string", + "include_metadata": true, + "key": "string", + "limit": 1, + "team_id": "string" + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "include_metadata": { + "example": true, + "type": "boolean" + }, + "key": { + "example": "string", + "type": "string" + }, + "limit": { + "example": 1, + "type": "integer" + }, + "team_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "team_id", + "key" + ], + "type": "object" + }, + "pattern": "api:chat:team:{team_id}:key:{key}", + "returns": { + "type": "object" + } + }, + { + "description": "Join a team-scoped transient (ephemeral) thread", + "name": "join_team_transient", + "params": { + "example": { + "after_cursor": "string", + "before_cursor": "string", + "include_metadata": true, + "key": "string", + "limit": 1, + "team_id": "string" + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "include_metadata": { + "example": true, + "type": "boolean" + }, + "key": { + "example": "string", + "type": "string" + }, + "limit": { + "example": 1, + "type": "integer" + }, + "team_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "team_id", + "key" + ], + "type": "object" + }, + "pattern": "api:chat:team:{team_id}:transient:{key}", + "returns": { + "type": "object" + } + }, + { + "description": "Join a user-scoped thread by ID", + "name": "join_user_thread", + "params": { + "example": { + "after_cursor": "string", + "before_cursor": "string", + "include_metadata": true, + "limit": 1, + "thread_id": "string" + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "include_metadata": { + "example": true, + "type": "boolean" + }, + "limit": { + "example": 1, + "type": "integer" + }, + "thread_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "thread_id" + ], + "type": "object" + }, + "pattern": "api:chat:user:thread:{thread_id}", + "returns": { + "type": "object" + } + }, + { + "description": "Join or create a user-scoped keyed thread", + "name": "join_user_keyed", + "params": { + "example": { + "after_cursor": "string", + "before_cursor": "string", + "include_metadata": true, + "key": "string", + "limit": 1 + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "include_metadata": { + "example": true, + "type": "boolean" + }, + "key": { + "example": "string", + "type": "string" + }, + "limit": { + "example": 1, + "type": "integer" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "pattern": "api:chat:user:key:{key}", + "returns": { + "type": "object" + } + }, + { + "description": "Join a user-scoped transient (ephemeral) thread", + "name": "join_user_transient", + "params": { + "example": { + "after_cursor": "string", + "before_cursor": "string", + "include_metadata": true, + "key": "string", + "limit": 1 + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "include_metadata": { + "example": true, + "type": "boolean" + }, + "key": { + "example": "string", + "type": "string" + }, + "limit": { + "example": 1, + "type": "integer" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "pattern": "api:chat:user:transient:{key}", + "returns": { + "type": "object" + } + } + ], + "messages": [ + { + "description": "Fork a sub-thread from an existing message", + "event": "api:chat:fork_thread", + "params": { + "example": { + "message_id": "string", + "title": "Example Title" + }, + "properties": { + "message_id": { + "example": "string", + "type": "string" + }, + "title": { + "example": "Example Title", + "type": "string" + } + }, + "required": [ + "message_id" + ], + "type": "object" + }, + "returns": { + "description": "Response returned after forking a chat thread. Contains the new thread, its initial chat-room snapshot, and the owning team when applicable.", + "example": { + "chat_model": { + "after_cursor": "string", + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "before_cursor": "string", + "is_transient": true, + "members": [ + { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "membership_type": "owner", + "type": "user", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + } + ], + "messages": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ], + "messages_loaded_on_last_update": 1, + "team": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "thread": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + } + }, + "team": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "thread": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + } + }, + "properties": { + "chat_model": { + "description": "Initial chat-room render snapshot for the forked thread, including members and loaded messages. `null` for transient threads whose room model is suppressed.", + "example": { + "after_cursor": "string", + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "before_cursor": "string", + "is_transient": true, + "members": [ + { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "membership_type": "owner", + "type": "user", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + } + ], + "messages": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ], + "messages_loaded_on_last_update": 1, + "team": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "thread": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + } + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor to pass when fetching messages newer than those in this snapshot. `null` when this snapshot already reflects the latest messages.", + "example": "string", + "type": "string" + }, + "agent": { + "description": "The agent associated with this chat room. `null` when no agent is attached.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints.", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "solution": { + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "before_cursor": { + "description": "Opaque cursor to pass when fetching messages older than those in this snapshot. `null` when the beginning of the thread history has been reached.", + "example": "string", + "type": "string" + }, + "is_transient": { + "description": "Whether this thread is ephemeral. Transient threads are not retained in long-term storage and may be deleted when the session ends.", + "example": true, + "type": "boolean" + }, + "members": { + "description": "All active members of the chat room, including both human users and agents.", + "example": [ + { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "membership_type": "owner", + "type": "user", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + } + ], + "items": { + "description": "A participant in a chat thread, which may be either a human user or an AI agent. Exactly one of `user` or `agent` is populated depending on `type`.", + "example": { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "membership_type": "owner", + "type": "user", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + }, + "properties": { + "agent": { + "description": "Full agent object for this member. Populated when `type` is `\"agent\"`; `null` for user members.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints.", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "solution": { + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "membership_type": { + "description": "Role of this member within the thread. Common values are `\"owner\"` and `\"member\"`. `null` when the membership type is not applicable.", + "example": "owner", + "type": "string" + }, + "type": { + "description": "Kind of participant. One of `\"user\"` (a human user) or `\"agent\"` (an AI agent).", + "example": "user", + "type": "string" + }, + "user": { + "description": "Full user object for this member. Populated when `type` is `\"user\"`; `null` for agent members.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "messages": { + "description": "The page of messages currently loaded for the thread, ordered chronologically. Use `before_cursor` or `after_cursor` to page through additional history.", + "example": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ], + "items": { + "description": "A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "example": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "items": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "example": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "items": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "example": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "items": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "example": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "items": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "messages_loaded_on_last_update": { + "description": "Number of messages that were added to the snapshot in the most recent incremental update. `null` on the initial load.", + "example": 1, + "type": "integer" + }, + "team": { + "description": "The team that owns this thread. `null` for threads scoped to an individual user rather than a team.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "acl": { + "description": "Access control list governing visibility and join permissions for this team. `null` when no ACL restrictions are applied and the team inherits default access rules.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the developer application this team belongs to (`dap_...`). `null` if the team is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "badges": { + "description": "Aggregated badge counts for the team, keyed by category. `null` when badge data is not loaded.", + "example": {}, + "type": "object" + }, + "created_at": { + "description": "When this team was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Human-readable description of the team's purpose. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Team ID (`tem_...`).", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "membership_status": { + "description": "The authenticated viewer's role on this team. One of `\"owner\"`, `\"admin\"`, or `\"member\"`. `null` if the viewer is not a member.", + "example": "member", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this team. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Display name of the team.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this team belongs to (`org_...`). `null` if the team is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this team is scoped to (`dsb_...`). `null` outside sandbox contexts.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "slug": { + "description": "URL-safe slug for the team, derived from the team name. `null` if not set.", + "example": "example-slug", + "type": "string" + }, + "updated_at": { + "description": "When this team was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "thread": { + "description": "The parent thread whose message history and membership this snapshot represents.", + "example": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + }, + "properties": { + "agent_user": { + "description": "ID of the agent that owns this thread (`agt_...`). `null` for user-owned or team-owned threads.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the thread was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "creator": { + "description": "User who created this thread. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if the creator is unknown.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "oneOf": [ + { + "type": "string" + }, + { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + }, + "description": { + "description": "Optional description or purpose statement for the thread. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Thread ID (`thr_...`).", + "example": "string", + "type": "string" + }, + "is_channel": { + "description": "Whether this thread operates as a channel — a multi-member broadcast-style conversation.", + "example": true, + "type": "boolean" + }, + "is_default": { + "description": "Whether this is the default thread for its owner. Each user or team has at most one default thread.", + "example": true, + "type": "boolean" + }, + "is_transient": { + "description": "Whether this thread is ephemeral and may be deleted automatically after a period of inactivity or when its TTL expires.", + "example": true, + "type": "boolean" + }, + "is_unlisted": { + "description": "Whether this thread is hidden from public discovery. Unlisted threads are accessible only to direct participants.", + "example": true, + "type": "boolean" + }, + "key": { + "description": "Application-defined stable key that uniquely identifies the thread within its scope. Useful for idempotent creation. `null` if not set.", + "example": "string", + "type": "string" + }, + "kind": { + "description": "Thread subtype: `\"standard\"` for ordinary threads, `\"slack_mirror\"` for the membership-strict mirror of a Slack channel, `\"slashwork_mirror\"` for the membership-strict mirror of a Slashwork group. Read-only — derived server-side at creation, never accepted from params.", + "example": "string", + "type": "string" + }, + "last_activity": { + "description": "When the most recent message was posted in this thread, falling back to the thread's creation time if it has no messages. Always populated on thread list endpoints (which order by it, after default threads); `null` on endpoints that don't compute activity enrichment.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "last_message_preview": { + "description": "Single-line snippet of the most recent message's text content (first non-empty line, truncated to 140 characters). Populated on thread list endpoints alongside `last_activity`; `null` when the thread has no messages, the latest message has no text content (e.g. attachment-only), or the endpoint doesn't compute activity enrichment.", + "example": "Sounds good — I'll ship the fix tomorrow.", + "type": "string" + }, + "last_message_sender": { + "description": "Display name of the sender of the most recent message — the same message `last_message_preview` snippets. Populated on thread list endpoints; `null` when the thread has no messages or the endpoint doesn't compute activity enrichment.", + "example": "Alice Chen", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the thread. Shape is application-defined; `null` if no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "muted": { + "description": "Whether the authenticated user has muted notifications for this thread. `true` suppresses all notification delivery.", + "example": true, + "type": "boolean" + }, + "org": { + "description": "ID of the organization this thread belongs to (`org_...`). `null` for threads outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent_message": { + "description": "The message that spawned this thread as a sub-thread. `null` for top-level threads.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "example": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "items": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "example": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "items": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "example": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "items": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "example": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "items": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "participant": { + "description": "Array of participant user IDs (`usr_...`) who are members of this thread.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "participants": { + "description": "Expanded participant user objects for each member of this thread. Populated only when the association is loaded.", + "example": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "items": { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "participating_actor": { + "description": "Composite actor identifiers for all participants currently active in this thread. Present only when actor enrichment is requested.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "participating_agents": { + "description": "Expanded agent objects for all agents participating in this thread. Present only when agent enrichment is requested.", + "example": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "An AI agent that can be configured with tools, routines, and skills, and invoked to handle conversations or tasks.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints.", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "solution": { + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "role": { + "description": "The authenticated user's membership role in this thread, e.g. `\"owner\"`, `\"member\"`, or `\"viewer\"`. `null` if the user is not a member.", + "example": "member", + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this thread is scoped to (`dsb_...`). `null` for production threads.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "settings": { + "description": "Per-thread configuration settings controlling AI agent behavior for this thread.", + "example": { + "agent_enabled": true + }, + "properties": { + "agent_enabled": { + "description": "Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured.", + "example": true, + "type": "boolean" + } + }, + "type": "object" + }, + "slug": { + "description": "URL-safe slug for the thread, used in human-readable permalinks. `null` if not assigned.", + "example": "example-slug", + "type": "string" + }, + "sub_threads": { + "description": "Threads that are nested under this thread as replies to a parent message. Present only when sub-thread enrichment is requested.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "tags": { + "description": "Status tags on the thread (e.g. `\"blocked\"`, `\"needs-review\"`). Edited by any thread participant via the `/threads/:thread/tags` endpoints and filterable on the thread list endpoints. Empty array if none set.", + "example": [ + "blocked", + "needs-review" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this thread (`team_...`). `null` for user-owned or agent-owned threads.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "title": { + "description": "Human-readable name of the thread. `null` if no title has been set.", + "example": "Example Title", + "type": "string" + }, + "ttl": { + "description": "Time-to-live in seconds after which the thread may be automatically cleaned up. `null` if the thread does not expire.", + "example": 3600, + "type": "integer" + }, + "unread_count": { + "description": "Number of messages in this thread that the authenticated user has not yet read. Present only when read-state enrichment is requested.", + "example": 5, + "type": "integer" + }, + "updated_at": { + "description": "When the thread was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user who owns this thread (`usr_...`). `null` for team-owned or agent-owned threads.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "visibility": { + "description": "Who can read the thread: `team` for every owning-team member, `restricted` for team-readable threads with an explicit roster, or `private` for roster-only access.", + "enum": [ + "team", + "restricted", + "private" + ], + "example": "team", + "type": "string" + } + }, + "required": [ + "id", + "visibility" + ], + "type": "object" + } + }, + "required": [ + "messages", + "members", + "thread", + "is_transient" + ], + "type": "object" + }, + "team": { + "description": "Team that owns the forked thread. Present only when the original thread was team-scoped; `null` for personal threads.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "acl": { + "description": "Access control list governing visibility and join permissions for this team. `null` when no ACL restrictions are applied and the team inherits default access rules.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the developer application this team belongs to (`dap_...`). `null` if the team is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "badges": { + "description": "Aggregated badge counts for the team, keyed by category. `null` when badge data is not loaded.", + "example": {}, + "type": "object" + }, + "created_at": { + "description": "When this team was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Human-readable description of the team's purpose. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Team ID (`tem_...`).", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "membership_status": { + "description": "The authenticated viewer's role on this team. One of `\"owner\"`, `\"admin\"`, or `\"member\"`. `null` if the viewer is not a member.", + "example": "member", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this team. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Display name of the team.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this team belongs to (`org_...`). `null` if the team is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this team is scoped to (`dsb_...`). `null` outside sandbox contexts.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "slug": { + "description": "URL-safe slug for the team, derived from the team name. `null` if not set.", + "example": "example-slug", + "type": "string" + }, + "updated_at": { + "description": "When this team was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "thread": { + "description": "The newly-created thread produced by the fork operation.", + "example": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + }, + "properties": { + "agent_user": { + "description": "ID of the agent that owns this thread (`agt_...`). `null` for user-owned or team-owned threads.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the thread was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "creator": { + "description": "User who created this thread. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if the creator is unknown.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "oneOf": [ + { + "type": "string" + }, + { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + }, + "description": { + "description": "Optional description or purpose statement for the thread. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Thread ID (`thr_...`).", + "example": "string", + "type": "string" + }, + "is_channel": { + "description": "Whether this thread operates as a channel — a multi-member broadcast-style conversation.", + "example": true, + "type": "boolean" + }, + "is_default": { + "description": "Whether this is the default thread for its owner. Each user or team has at most one default thread.", + "example": true, + "type": "boolean" + }, + "is_transient": { + "description": "Whether this thread is ephemeral and may be deleted automatically after a period of inactivity or when its TTL expires.", + "example": true, + "type": "boolean" + }, + "is_unlisted": { + "description": "Whether this thread is hidden from public discovery. Unlisted threads are accessible only to direct participants.", + "example": true, + "type": "boolean" + }, + "key": { + "description": "Application-defined stable key that uniquely identifies the thread within its scope. Useful for idempotent creation. `null` if not set.", + "example": "string", + "type": "string" + }, + "kind": { + "description": "Thread subtype: `\"standard\"` for ordinary threads, `\"slack_mirror\"` for the membership-strict mirror of a Slack channel, `\"slashwork_mirror\"` for the membership-strict mirror of a Slashwork group. Read-only — derived server-side at creation, never accepted from params.", + "example": "string", + "type": "string" + }, + "last_activity": { + "description": "When the most recent message was posted in this thread, falling back to the thread's creation time if it has no messages. Always populated on thread list endpoints (which order by it, after default threads); `null` on endpoints that don't compute activity enrichment.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "last_message_preview": { + "description": "Single-line snippet of the most recent message's text content (first non-empty line, truncated to 140 characters). Populated on thread list endpoints alongside `last_activity`; `null` when the thread has no messages, the latest message has no text content (e.g. attachment-only), or the endpoint doesn't compute activity enrichment.", + "example": "Sounds good — I'll ship the fix tomorrow.", + "type": "string" + }, + "last_message_sender": { + "description": "Display name of the sender of the most recent message — the same message `last_message_preview` snippets. Populated on thread list endpoints; `null` when the thread has no messages or the endpoint doesn't compute activity enrichment.", + "example": "Alice Chen", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the thread. Shape is application-defined; `null` if no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "muted": { + "description": "Whether the authenticated user has muted notifications for this thread. `true` suppresses all notification delivery.", + "example": true, + "type": "boolean" + }, + "org": { + "description": "ID of the organization this thread belongs to (`org_...`). `null` for threads outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent_message": { + "description": "The message that spawned this thread as a sub-thread. `null` for top-level threads.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "example": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "items": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "example": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "items": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "example": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "items": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "example": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "items": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "participant": { + "description": "Array of participant user IDs (`usr_...`) who are members of this thread.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "participants": { + "description": "Expanded participant user objects for each member of this thread. Populated only when the association is loaded.", + "example": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "items": { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "participating_actor": { + "description": "Composite actor identifiers for all participants currently active in this thread. Present only when actor enrichment is requested.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "participating_agents": { + "description": "Expanded agent objects for all agents participating in this thread. Present only when agent enrichment is requested.", + "example": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "An AI agent that can be configured with tools, routines, and skills, and invoked to handle conversations or tasks.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints.", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "solution": { + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "role": { + "description": "The authenticated user's membership role in this thread, e.g. `\"owner\"`, `\"member\"`, or `\"viewer\"`. `null` if the user is not a member.", + "example": "member", + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this thread is scoped to (`dsb_...`). `null` for production threads.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "settings": { + "description": "Per-thread configuration settings controlling AI agent behavior for this thread.", + "example": { + "agent_enabled": true + }, + "properties": { + "agent_enabled": { + "description": "Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured.", + "example": true, + "type": "boolean" + } + }, + "type": "object" + }, + "slug": { + "description": "URL-safe slug for the thread, used in human-readable permalinks. `null` if not assigned.", + "example": "example-slug", + "type": "string" + }, + "sub_threads": { + "description": "Threads that are nested under this thread as replies to a parent message. Present only when sub-thread enrichment is requested.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "tags": { + "description": "Status tags on the thread (e.g. `\"blocked\"`, `\"needs-review\"`). Edited by any thread participant via the `/threads/:thread/tags` endpoints and filterable on the thread list endpoints. Empty array if none set.", + "example": [ + "blocked", + "needs-review" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this thread (`team_...`). `null` for user-owned or agent-owned threads.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "title": { + "description": "Human-readable name of the thread. `null` if no title has been set.", + "example": "Example Title", + "type": "string" + }, + "ttl": { + "description": "Time-to-live in seconds after which the thread may be automatically cleaned up. `null` if the thread does not expire.", + "example": 3600, + "type": "integer" + }, + "unread_count": { + "description": "Number of messages in this thread that the authenticated user has not yet read. Present only when read-state enrichment is requested.", + "example": 5, + "type": "integer" + }, + "updated_at": { + "description": "When the thread was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user who owns this thread (`usr_...`). `null` for team-owned or agent-owned threads.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "visibility": { + "description": "Who can read the thread: `team` for every owning-team member, `restricted` for team-readable threads with an explicit roster, or `private` for roster-only access.", + "enum": [ + "team", + "restricted", + "private" + ], + "example": "team", + "type": "string" + } + }, + "required": [ + "id", + "visibility" + ], + "type": "object" + } + }, + "required": [ + "thread" + ], + "type": "object" + } + }, + { + "description": "Mark a thread as read up to a given message", + "event": "api:chat:mark_thread_read", + "params": { + "example": { + "message_id": "string" + }, + "properties": { + "message_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "message_id" + ], + "type": "object" + }, + "returns": { + "description": "Response returned after marking a chat thread as read. Confirms that the read marker was successfully recorded for the authenticated user.", + "example": { + "success": true + }, + "properties": { + "success": { + "description": "Indicates whether the read marker was successfully applied. Always `true` on success; errors are returned as channel error replies rather than a `false` value here.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "success" + ], + "type": "object" + } + }, + { + "description": "List all messages in the current thread", + "event": "api:chat:list_messages", + "params": { + "properties": {}, + "type": "object" + }, + "returns": { + "description": "Response returned when listing the messages of a joined chat thread. Contains the set of messages currently loaded for the thread.", + "example": { + "messages": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ] + }, + "properties": { + "messages": { + "description": "Ordered array of message objects currently loaded for the thread, from oldest to newest. Use the `load_more_messages` channel message to fetch earlier pages.", + "example": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ], + "items": { + "description": "A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "example": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "items": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "example": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "items": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "example": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "items": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "example": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "items": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "messages" + ], + "type": "object" + } + }, + { + "description": "Load additional messages with cursor-based pagination", + "event": "api:chat:load_more_messages", + "params": { + "example": { + "after_cursor": "string", + "before_cursor": "string", + "include_metadata": true, + "limit": 1 + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "include_metadata": { + "example": true, + "type": "boolean" + }, + "limit": { + "example": 1, + "type": "integer" + } + }, + "type": "object" + }, + "returns": { + "description": "Response returned after loading an additional page of chat messages. Contains a refreshed chat-room snapshot with the newly-fetched messages merged in.", + "example": { + "data": { + "after_cursor": "string", + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "before_cursor": "string", + "is_transient": true, + "members": [ + { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "membership_type": "owner", + "type": "user", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + } + ], + "messages": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ], + "messages_loaded_on_last_update": 1, + "team": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "thread": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + } + } + }, + "properties": { + "data": { + "description": "Updated chat-room snapshot for the thread, incorporating the newly-loaded page of messages alongside any previously loaded messages.", + "example": { + "after_cursor": "string", + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "before_cursor": "string", + "is_transient": true, + "members": [ + { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "membership_type": "owner", + "type": "user", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + } + ], + "messages": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ], + "messages_loaded_on_last_update": 1, + "team": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "thread": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + } + }, + "properties": { + "after_cursor": { + "description": "Opaque cursor to pass when fetching messages newer than those in this snapshot. `null` when this snapshot already reflects the latest messages.", + "example": "string", + "type": "string" + }, + "agent": { + "description": "The agent associated with this chat room. `null` when no agent is attached.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints.", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "solution": { + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "before_cursor": { + "description": "Opaque cursor to pass when fetching messages older than those in this snapshot. `null` when the beginning of the thread history has been reached.", + "example": "string", + "type": "string" + }, + "is_transient": { + "description": "Whether this thread is ephemeral. Transient threads are not retained in long-term storage and may be deleted when the session ends.", + "example": true, + "type": "boolean" + }, + "members": { + "description": "All active members of the chat room, including both human users and agents.", + "example": [ + { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "membership_type": "owner", + "type": "user", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + } + ], + "items": { + "description": "A participant in a chat thread, which may be either a human user or an AI agent. Exactly one of `user` or `agent` is populated depending on `type`.", + "example": { + "agent": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "membership_type": "owner", + "type": "user", + "user": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + }, + "properties": { + "agent": { + "description": "Full agent object for this member. Populated when `type` is `\"agent\"`; `null` for user members.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints.", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "solution": { + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "membership_type": { + "description": "Role of this member within the thread. Common values are `\"owner\"` and `\"member\"`. `null` when the membership type is not applicable.", + "example": "owner", + "type": "string" + }, + "type": { + "description": "Kind of participant. One of `\"user\"` (a human user) or `\"agent\"` (an AI agent).", + "example": "user", + "type": "string" + }, + "user": { + "description": "Full user object for this member. Populated when `type` is `\"user\"`; `null` for agent members.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "messages": { + "description": "The page of messages currently loaded for the thread, ordered chronologically. Use `before_cursor` or `after_cursor` to page through additional history.", + "example": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + ], + "items": { + "description": "A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "example": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "items": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "example": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "items": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "example": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "items": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "example": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "items": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "messages_loaded_on_last_update": { + "description": "Number of messages that were added to the snapshot in the most recent incremental update. `null` on the initial load.", + "example": 1, + "type": "integer" + }, + "team": { + "description": "The team that owns this thread. `null` for threads scoped to an individual user rather than a team.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "badges": {}, + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "id": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "membership_status": "member", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "slug": "example-slug", + "updated_at": "2024-01-01T00:00:00Z" + }, + "properties": { + "acl": { + "description": "Access control list governing visibility and join permissions for this team. `null` when no ACL restrictions are applied and the team inherits default access rules.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the developer application this team belongs to (`dap_...`). `null` if the team is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "badges": { + "description": "Aggregated badge counts for the team, keyed by category. `null` when badge data is not loaded.", + "example": {}, + "type": "object" + }, + "created_at": { + "description": "When this team was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Human-readable description of the team's purpose. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Team ID (`tem_...`).", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "membership_status": { + "description": "The authenticated viewer's role on this team. One of `\"owner\"`, `\"admin\"`, or `\"member\"`. `null` if the viewer is not a member.", + "example": "member", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to this team. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Display name of the team.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this team belongs to (`org_...`). `null` if the team is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this team is scoped to (`dsb_...`). `null` outside sandbox contexts.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "slug": { + "description": "URL-safe slug for the team, derived from the team name. `null` if not set.", + "example": "example-slug", + "type": "string" + }, + "updated_at": { + "description": "When this team was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "thread": { + "description": "The parent thread whose message history and membership this snapshot represents.", + "example": { + "agent_user": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "creator": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "description": "An example description.", + "id": "string", + "is_channel": true, + "is_default": true, + "is_transient": true, + "is_unlisted": true, + "key": "string", + "kind": "string", + "last_activity": "2024-01-01T00:00:00Z", + "last_message_preview": "Sounds good — I'll ship the fix tomorrow.", + "last_message_sender": "Alice Chen", + "metadata": { + "key": "value" + }, + "muted": true, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "parent_message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "participant": [ + "string" + ], + "participants": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "participating_actor": [ + "string" + ], + "participating_agents": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "role": "member", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "settings": { + "agent_enabled": true + }, + "slug": "example-slug", + "sub_threads": [ + {} + ], + "tags": [ + "blocked", + "needs-review" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "title": "Example Title", + "ttl": 3600, + "unread_count": 5, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "visibility": "team" + }, + "properties": { + "agent_user": { + "description": "ID of the agent that owns this thread (`agt_...`). `null` for user-owned or team-owned threads.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the thread was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "creator": { + "description": "User who created this thread. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if the creator is unknown.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "oneOf": [ + { + "type": "string" + }, + { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + }, + "description": { + "description": "Optional description or purpose statement for the thread. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "id": { + "description": "Thread ID (`thr_...`).", + "example": "string", + "type": "string" + }, + "is_channel": { + "description": "Whether this thread operates as a channel — a multi-member broadcast-style conversation.", + "example": true, + "type": "boolean" + }, + "is_default": { + "description": "Whether this is the default thread for its owner. Each user or team has at most one default thread.", + "example": true, + "type": "boolean" + }, + "is_transient": { + "description": "Whether this thread is ephemeral and may be deleted automatically after a period of inactivity or when its TTL expires.", + "example": true, + "type": "boolean" + }, + "is_unlisted": { + "description": "Whether this thread is hidden from public discovery. Unlisted threads are accessible only to direct participants.", + "example": true, + "type": "boolean" + }, + "key": { + "description": "Application-defined stable key that uniquely identifies the thread within its scope. Useful for idempotent creation. `null` if not set.", + "example": "string", + "type": "string" + }, + "kind": { + "description": "Thread subtype: `\"standard\"` for ordinary threads, `\"slack_mirror\"` for the membership-strict mirror of a Slack channel, `\"slashwork_mirror\"` for the membership-strict mirror of a Slashwork group. Read-only — derived server-side at creation, never accepted from params.", + "example": "string", + "type": "string" + }, + "last_activity": { + "description": "When the most recent message was posted in this thread, falling back to the thread's creation time if it has no messages. Always populated on thread list endpoints (which order by it, after default threads); `null` on endpoints that don't compute activity enrichment.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "last_message_preview": { + "description": "Single-line snippet of the most recent message's text content (first non-empty line, truncated to 140 characters). Populated on thread list endpoints alongside `last_activity`; `null` when the thread has no messages, the latest message has no text content (e.g. attachment-only), or the endpoint doesn't compute activity enrichment.", + "example": "Sounds good — I'll ship the fix tomorrow.", + "type": "string" + }, + "last_message_sender": { + "description": "Display name of the sender of the most recent message — the same message `last_message_preview` snippets. Populated on thread list endpoints; `null` when the thread has no messages or the endpoint doesn't compute activity enrichment.", + "example": "Alice Chen", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the thread. Shape is application-defined; `null` if no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "muted": { + "description": "Whether the authenticated user has muted notifications for this thread. `true` suppresses all notification delivery.", + "example": true, + "type": "boolean" + }, + "org": { + "description": "ID of the organization this thread belongs to (`org_...`). `null` for threads outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent_message": { + "description": "The message that spawned this thread as a sub-thread. `null` for top-level threads.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "example": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "items": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "example": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "items": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "example": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "items": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "example": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "items": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "participant": { + "description": "Array of participant user IDs (`usr_...`) who are members of this thread.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "participants": { + "description": "Expanded participant user objects for each member of this thread. Populated only when the association is loaded.", + "example": [ + { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + } + ], + "items": { + "description": "A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API.", + "example": { + "alias": "jdoe", + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "app_name": "Example Name", + "email": "user@example.com", + "id": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "is_system_user": true, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "org_role": "member", + "org_slug": "example-slug", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "sandbox_name": "Example Name" + }, + "properties": { + "alias": { + "description": "Short handle or alias for the user. `null` if not set.", + "example": "jdoe", + "type": "string" + }, + "app": { + "description": "ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app.", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "app_name": { + "description": "Display name of the user's app. `null` when the app association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "email": { + "description": "Email address of the user.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "User ID (`usr_...`).", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_system_user": { + "description": "`true` if this account is an internal system user rather than a human. System users are created automatically by the platform.", + "example": true, + "type": "boolean" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the user. Defaults to an empty object.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Full display name of the user. `null` if the user has not set a name.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + }, + "org_role": { + "description": "Role of the user within their organization. One of `\"admin\"`, `\"member\"`, or `\"viewer\"`. `null` when the user is not a member of any organization.", + "example": "member", + "type": "string" + }, + "org_slug": { + "description": "Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller.", + "example": "example-slug", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "sandbox_name": { + "description": "Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "participating_actor": { + "description": "Composite actor identifiers for all participants currently active in this thread. Present only when actor enrichment is requested.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "participating_agents": { + "description": "Expanded agent objects for all agents participating in this thread. Present only when agent enrichment is requested.", + "example": [ + { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "An AI agent that can be configured with tools, routines, and skills, and invoked to handle conversations or tasks.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "app": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "created_at": "2024-01-01T00:00:00Z", + "default_model": "claude-3-7-sonnet-latest", + "description": "An example description.", + "email": "user@example.com", + "id": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "identity": "You are a helpful assistant that answers questions about ArchAstro products.", + "last_applied_template_config": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_name": "Example Name", + "originator": "deploy-pipeline", + "phone_number": "+15555550123", + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "source_solution": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "template_upgrade_available": true, + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "acl": { + "description": "Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "ID of the application that owns this agent (`dap_...`).", + "example": "dap_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_at": { + "description": "When the agent was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `\"claude-3-7-sonnet-latest\"`).", + "example": "claude-3-7-sonnet-latest", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the agent does. `null` if not set.", + "example": "An example description.", + "type": "string" + }, + "email": { + "description": "Email address provisioned for this agent. `null` if email delivery is not configured.", + "example": "user@example.com", + "type": "string" + }, + "id": { + "description": "Agent ID (`agi_...`).", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "identity": { + "description": "System-level identity prompt that shapes the agent's persona and behavior.", + "example": "You are a helpful assistant that answers questions about ArchAstro products.", + "type": "string" + }, + "last_applied_template_config": { + "description": "ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents.", + "example": "cfg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "lookup_key": { + "description": "Stable, user-defined identifier for this agent within the application. Unique per app.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the agent. Not interpreted by the platform.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable display name for the agent. `null` if not set.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_name": { + "description": "Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded.", + "example": "Example Name", + "type": "string" + }, + "originator": { + "description": "Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name).", + "example": "deploy-pipeline", + "type": "string" + }, + "phone_number": { + "description": "Phone number provisioned for this agent. `null` if SMS is not configured.", + "example": "+15555550123", + "type": "string" + }, + "sandbox": { + "description": "ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints.", + "example": { + "current_solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "solution": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "template": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + } + }, + "properties": { + "current_solution": { + "description": "Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "solution": { + "description": "Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution.", + "example": { + "category_keys": [ + "string" + ], + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "events": {}, + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "image_url": "https://example.com", + "kind": "Solution", + "latest_solution": "id_0aBcDeFgHiJkLmNoPqRsTu", + "latest_version": "1.0.0", + "lookup_key": "string", + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "org_logo": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "org_name": "Example Name", + "org_slug": "example-slug", + "owners": [ + "string" + ], + "readme_url": "https://example.com", + "screenshot_urls": [ + "https://example.com" + ], + "solution_id": "01234567-89ab-cdef-0123-456789abcdef", + "solution_version": "1.2.0", + "tag_keys": [ + "string" + ], + "template_kind": "AgentTemplate", + "templates": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "updated_at": "2024-01-01T00:00:00Z", + "upgrade_available": true, + "virtual_path": "string" + }, + "properties": { + "category_keys": { + "description": "Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "When the Solution config was first imported (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one.", + "example": "An example description.", + "type": "string" + }, + "events": { + "description": "Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none.", + "example": {}, + "type": "object" + }, + "id": { + "description": "Solution config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_url": { + "description": "Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only.", + "example": "https://example.com", + "type": "string" + }, + "kind": { + "description": "Resource type. Always `\"Solution\"`.", + "example": "Solution", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise.", + "example": "1.0.0", + "type": "string" + }, + "lookup_key": { + "description": "The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-facing display name declared in the Solution body. `null` when the Solution body does not set one.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "org_logo": { + "description": "Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "org_name": { + "description": "Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`.", + "example": "Example Name", + "type": "string" + }, + "org_slug": { + "description": "Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve.", + "example": "example-slug", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "screenshot_urls": { + "description": "Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only.", + "example": [ + "https://example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "solution_id": { + "description": "Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "solution_version": { + "description": "Semver string declared in the Solution body (e.g. `\"1.2.0\"`). `null` when the body does not declare a version.", + "example": "1.2.0", + "type": "string" + }, + "tag_keys": { + "description": "Freeform tag keys declared in the Solution body. An empty array when the body declares none.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "example": "AgentTemplate", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "example": [ + { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + } + ], + "items": { + "description": "Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity.", + "example": { + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "AgentTemplate", + "lookup_key": "string", + "name": "Example Name", + "readme_url": "https://example.com", + "virtual_path": "string" + }, + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel.", + "example": "An example description.", + "type": "string" + }, + "details": { + "description": "Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "description": "AutomationTemplate-specific details exposed by a Solution template summary.", + "example": { + "automation_type": "string", + "invoke_contract": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "type": "automation" + }, + "properties": { + "automation_type": { + "description": "Automation execution type (`invoked`, `scheduled`, or `trigger`).", + "example": "string", + "type": "string" + }, + "invoke_contract": { + "description": "Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning.", + "example": { + "input_schema": {}, + "participants": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "prefills": { + "participants": {}, + "payload": {} + } + }, + "properties": { + "input_schema": { + "description": "JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured.", + "example": {}, + "type": "object" + }, + "participants": { + "description": "Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs.", + "example": [ + { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + } + ], + "items": { + "description": "A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot.", + "example": { + "description": "An example description.", + "name": "reporter", + "required": true, + "type": "agent_user" + }, + "properties": { + "description": { + "description": "Workflow-authored explanation of the slot's role. `null` when the workflow declares none.", + "example": "An example description.", + "type": "string" + }, + "name": { + "description": "The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking.", + "example": "reporter", + "type": "string" + }, + "required": { + "description": "Whether the workflow requires this slot to be filled for the run to complete its embedded stages.", + "example": true, + "type": "boolean" + }, + "type": { + "description": "The kind of principal the slot accepts. Currently always `\"agent_user\"` — the value supplied at invoke is an agent ID (`agi_...`).", + "example": "agent_user", + "type": "string" + } + }, + "required": [ + "name", + "type", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "prefills": { + "description": "Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected.", + "example": { + "participants": {}, + "payload": {} + }, + "properties": { + "participants": { + "description": "Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly.", + "example": {}, + "type": "object" + }, + "payload": { + "description": "Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected.", + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "prefills" + ], + "type": "object" + }, + "type": { + "default": "automation", + "description": "Template-details discriminator. Always `automation` for this variant.", + "enum": [ + "automation" + ], + "example": "automation", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`). `null` for inline-only templates.", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "example": "AgentTemplate", + "type": "string" + }, + "lookup_key": { + "description": "Lookup key stamped on the template config at import time. `null` when no lookup key was assigned.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "example": "Example Name", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "example": "https://example.com", + "type": "string" + }, + "virtual_path": { + "description": "Stable virtual path assigned to the template config. `null` when no virtual path was set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "When the Solution config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "`true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows.", + "example": true, + "type": "boolean" + }, + "virtual_path": { + "description": "The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from.", + "example": { + "created_at": "2024-01-01T00:00:00Z", + "description": "An example description.", + "display_name": "Example Name", + "id": "id_0aBcDeFgHiJkLmNoPqRsTu", + "kind": "agent_tool_template", + "lookup_key": "string", + "name": "Example Name", + "updated_at": "2024-01-01T00:00:00Z", + "virtual_path": "string" + }, + "properties": { + "created_at": { + "description": "When this template config was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Description of the template from the config body. `null` if the current version has no `description` field.", + "example": "An example description.", + "type": "string" + }, + "display_name": { + "description": "Human-readable display name from the config body. `null` if the current version has no `display_name` field.", + "example": "Example Name", + "type": "string" + }, + "id": { + "description": "Template config ID (`cfg_...`).", + "example": "id_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "kind": { + "description": "Config kind identifier for this template (e.g. `\"agent_tool_template\"`).", + "example": "agent_tool_template", + "type": "string" + }, + "lookup_key": { + "description": "Stable lookup key assigned to this template config. `null` if no lookup key is set.", + "example": "string", + "type": "string" + }, + "name": { + "description": "Template name as stored in the config body. `null` if the current version has no `name` field.", + "example": "Example Name", + "type": "string" + }, + "updated_at": { + "description": "When this template config was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Virtual filesystem path for this template config. `null` if not set.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "template_upgrade_available": { + "description": "True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`).", + "example": true, + "type": "boolean" + }, + "updated_at": { + "description": "When the agent was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "role": { + "description": "The authenticated user's membership role in this thread, e.g. `\"owner\"`, `\"member\"`, or `\"viewer\"`. `null` if the user is not a member.", + "example": "member", + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this thread is scoped to (`dsb_...`). `null` for production threads.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "settings": { + "description": "Per-thread configuration settings controlling AI agent behavior for this thread.", + "example": { + "agent_enabled": true + }, + "properties": { + "agent_enabled": { + "description": "Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured.", + "example": true, + "type": "boolean" + } + }, + "type": "object" + }, + "slug": { + "description": "URL-safe slug for the thread, used in human-readable permalinks. `null` if not assigned.", + "example": "example-slug", + "type": "string" + }, + "sub_threads": { + "description": "Threads that are nested under this thread as replies to a parent message. Present only when sub-thread enrichment is requested.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "tags": { + "description": "Status tags on the thread (e.g. `\"blocked\"`, `\"needs-review\"`). Edited by any thread participant via the `/threads/:thread/tags` endpoints and filterable on the thread list endpoints. Empty array if none set.", + "example": [ + "blocked", + "needs-review" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this thread (`team_...`). `null` for user-owned or agent-owned threads.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "title": { + "description": "Human-readable name of the thread. `null` if no title has been set.", + "example": "Example Title", + "type": "string" + }, + "ttl": { + "description": "Time-to-live in seconds after which the thread may be automatically cleaned up. `null` if the thread does not expire.", + "example": 3600, + "type": "integer" + }, + "unread_count": { + "description": "Number of messages in this thread that the authenticated user has not yet read. Present only when read-state enrichment is requested.", + "example": 5, + "type": "integer" + }, + "updated_at": { + "description": "When the thread was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user who owns this thread (`usr_...`). `null` for team-owned or agent-owned threads.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "visibility": { + "description": "Who can read the thread: `team` for every owning-team member, `restricted` for team-readable threads with an explicit roster, or `private` for roster-only access.", + "enum": [ + "team", + "restricted", + "private" + ], + "example": "team", + "type": "string" + } + }, + "required": [ + "id", + "visibility" + ], + "type": "object" + } + }, + "required": [ + "messages", + "members", + "thread", + "is_transient" + ], + "type": "object" + } + }, + "required": [ + "data" + ], + "type": "object" + } + }, + { + "description": "Post a new message with optional uploads and reply-to", + "event": "api:chat:post_message", + "params": { + "example": { + "content": "string", + "idempotency_key": "string", + "reply_to": "string", + "uploads": [ + {} + ] + }, + "properties": { + "content": { + "example": "string", + "type": "string" + }, + "idempotency_key": { + "example": "string", + "type": "string" + }, + "reply_to": { + "example": "string", + "type": "string" + }, + "uploads": { + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "content" + ], + "type": "object" + }, + "returns": { + "description": "Response returned after successfully posting a message to a chat thread. Contains the persisted message object echoed back to the sender.", + "example": { + "message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + }, + "properties": { + "message": { + "description": "The message that was created and stored. Contains the full message object including its assigned ID, author, content, and timestamps.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "example": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "items": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "example": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "items": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "example": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "items": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "example": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "items": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + }, + "required": [ + "message" + ], + "type": "object" + } + }, + { + "description": "Post a simple text message", + "event": "api:chat:post_simple_message", + "params": { + "example": { + "content": "string", + "idempotency_key": "string", + "reply_to": "string" + }, + "properties": { + "content": { + "example": "string", + "type": "string" + }, + "idempotency_key": { + "example": "string", + "type": "string" + }, + "reply_to": { + "example": "string", + "type": "string" + } + }, + "type": "object" + }, + "returns": { + "description": "Response returned after successfully posting a message to a chat thread. Contains the persisted message object echoed back to the sender.", + "example": { + "message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + } + }, + "properties": { + "message": { + "description": "The message that was created and stored. Contains the full message object including its assigned ID, author, content, and timestamps.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "example": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "items": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "example": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "items": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "example": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "items": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "example": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "items": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + }, + "required": [ + "message" + ], + "type": "object" + } + }, + { + "description": "Edit an existing message's content", + "event": "api:chat:edit_message", + "params": { + "example": { + "content": "string", + "message_id": "string" + }, + "properties": { + "content": { + "example": "string", + "type": "string" + }, + "message_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "message_id", + "content" + ], + "type": "object" + }, + "returns": { + "description": "Empty acknowledgement payload returned by channel message handlers that produce no data. The wire envelope is `{\"status\": \"ok\", \"response\": {}}`.", + "properties": {}, + "type": "object" + } + }, + { + "description": "Delete a message", + "event": "api:chat:delete_message", + "params": { + "example": { + "message_id": "string" + }, + "properties": { + "message_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "message_id" + ], + "type": "object" + }, + "returns": { + "description": "Empty acknowledgement payload returned by channel message handlers that produce no data. The wire envelope is `{\"status\": \"ok\", \"response\": {}}`.", + "properties": {}, + "type": "object" + } + }, + { + "description": "Add an emoji reaction to a message", + "event": "api:chat:add_reaction", + "params": { + "example": { + "emoji": "string", + "message_id": "string" + }, + "properties": { + "emoji": { + "example": "string", + "type": "string" + }, + "message_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "message_id", + "emoji" + ], + "type": "object" + }, + "returns": { + "description": "Empty acknowledgement payload returned by channel message handlers that produce no data. The wire envelope is `{\"status\": \"ok\", \"response\": {}}`.", + "properties": {}, + "type": "object" + } + }, + { + "description": "Remove an emoji reaction from a message", + "event": "api:chat:remove_reaction", + "params": { + "example": { + "emoji": "string", + "message_id": "string" + }, + "properties": { + "emoji": { + "example": "string", + "type": "string" + }, + "message_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "message_id", + "emoji" + ], + "type": "object" + }, + "returns": { + "description": "Empty acknowledgement payload returned by channel message handlers that produce no data. The wire envelope is `{\"status\": \"ok\", \"response\": {}}`.", + "properties": {}, + "type": "object" + } + }, + { + "description": "Signal that the current user has started or stopped typing in the thread", + "event": "api:chat:typing", + "params": { + "example": { + "is_typing": true + }, + "properties": { + "is_typing": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "is_typing" + ], + "type": "object" + }, + "returns": { + "description": "Empty acknowledgement payload returned by channel message handlers that produce no data. The wire envelope is `{\"status\": \"ok\", \"response\": {}}`.", + "properties": {}, + "type": "object" + } + } + ], + "name": "ApiChatChannel", + "pushes": [ + { + "description": "Broadcast when a new message is added to a thread", + "event": "message_added", + "payload": { + "example": { + "after_cursor": "string", + "before_cursor": "string", + "message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "thread_id": "string" + }, + "properties": { + "after_cursor": { + "example": "string", + "type": "string" + }, + "before_cursor": { + "example": "string", + "type": "string" + }, + "message": { + "description": "A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "example": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "items": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "example": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "items": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "example": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "items": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "example": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "items": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "thread_id": { + "example": "string", + "type": "string" + } + }, + "type": "object" + } + }, + { + "description": "Broadcast when a message is updated or removed", + "event": "message_updated", + "payload": { + "example": { + "message": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "thread_id": "string" + }, + "properties": { + "message": { + "description": "A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "properties": { + "acl": { + "description": "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else.", + "example": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "grants": { + "description": "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`.", + "example": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "A single access-control grant that pairs a principal with the set of actions it is allowed to perform.", + "example": { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + }, + "properties": { + "actions": { + "description": "Array of action strings the principal is permitted to perform, e.g. `[\"read\", \"write\"]`. Must contain at least one entry.", + "example": [ + "read", + "write" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "The identifier of the principal. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`; omit entirely when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal receiving the grant. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`.", + "example": [ + { + "principal": "string", + "principal_type": "user" + } + ], + "items": { + "description": "Identifies a principal to be removed from an access-control list.", + "example": { + "principal": "string", + "principal_type": "user" + }, + "properties": { + "principal": { + "description": "The identifier of the principal to remove. A string ID for `\"user\"`, `\"team\"`, `\"org\"`, and `\"agent\"` types; one of `\"admin\"`, `\"member\"`, or `\"viewer\"` for `\"org_role\"`. Omit when `principal_type` is `\"everyone\"`.", + "example": "string", + "type": "string" + }, + "principal_type": { + "description": "The kind of principal to remove. One of `\"user\"`, `\"team\"`, `\"org\"`, `\"org_role\"`, `\"agent\"`, or `\"everyone\"`.", + "example": "user", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "actors": { + "description": "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.", + "example": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "items": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "agent": { + "description": "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "agent_mode": { + "description": "Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.", + "enum": [ + "cli", + "embedded" + ], + "example": "cli", + "type": "string" + }, + "attachments": { + "description": "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.", + "example": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "items": { + "description": "A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action.", + "example": { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + }, + "properties": { + "content_type": { + "description": "MIME type of the attached file, e.g. `\"image/png\"` or `\"application/pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "description": { + "description": "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types.", + "example": "An example description.", + "type": "string" + }, + "filename": { + "description": "Original filename of the attached file, e.g. `\"report.pdf\"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "id": { + "description": "Unique identifier for this attachment within the message.", + "example": "string", + "type": "string" + }, + "image_height": { + "description": "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "image_source": { + "description": "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "image_url": { + "description": "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise.", + "example": "https://example.com", + "type": "string" + }, + "image_width": { + "description": "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "media_type": { + "description": "The media category, e.g. `\"video\"` or `\"audio\"`. Present on `media` type only. `null` otherwise.", + "example": "application/json", + "type": "string" + }, + "name": { + "description": "Display name of the media item. Present on `media` type only. `null` otherwise.", + "example": "Example Name", + "type": "string" + }, + "object": { + "description": "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types.", + "example": {}, + "type": "object" + }, + "title": { + "description": "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types.", + "example": "Example Title", + "type": "string" + }, + "type": { + "description": "The attachment type. One of `\"file\"`, `\"scraped_link\"`, `\"artifact\"`, `\"task\"`, `\"media\"`, `\"action\"`, or `\"chart\"`. Determines which additional fields are present.", + "example": "file", + "type": "string" + }, + "url": { + "description": "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types.", + "example": "https://example.com", + "type": "string" + }, + "variants": { + "description": "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise.", + "example": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "items": { + "description": "A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time.", + "example": { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + }, + "properties": { + "content_type": { + "description": "MIME type of this variant's file (e.g., `\"image/jpeg\"`, `\"video/mp4\"`). `null` if the file is not loaded.", + "example": "application/json", + "type": "string" + }, + "created_at": { + "description": "When this variant was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "file": { + "description": "ID of the underlying storage file that backs this variant (`fil_...`).", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded file for this variant. `null` if the file is not loaded.", + "example": "string", + "type": "string" + }, + "height": { + "description": "Height of this variant in pixels. `null` if not recorded.", + "example": 600, + "type": "integer" + }, + "id": { + "description": "Media variant ID (`mvr_...`).", + "example": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "image_source": { + "description": "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + }, + "updated_at": { + "description": "When this variant was last updated (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable.", + "example": "https://example.com", + "type": "string" + }, + "variant_key": { + "description": "Identifier for this variant's processing tier. Common values include `\"original\"` (the unmodified upload) and `\"thumbnail\"` (a resized preview).", + "example": "original", + "type": "string" + }, + "width": { + "description": "Width of this variant in pixels. `null` if not recorded.", + "example": 800, + "type": "integer" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "version": { + "description": "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise.", + "example": 1, + "type": "integer" + }, + "width": { + "description": "Width in pixels of the media item. Present on `media` type only. `null` otherwise.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "id", + "type" + ], + "type": "object" + }, + "type": "array" + }, + "branched_thread": { + "description": "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread.", + "example": "string", + "type": "string" + }, + "content": { + "description": "Text content of the message. `null` for messages that contain only attachments.", + "example": "Hello, how can I help you today?", + "type": "string" + }, + "created_at": { + "description": "When the message was posted (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "has_replies": { + "description": "Whether this message has at least one reply. Only present when explicitly requested or computed by the server.", + "example": true, + "type": "boolean" + }, + "id": { + "description": "Message ID (`msg_...`).", + "example": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "idempotency_key": { + "description": "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one.", + "example": "01234567-89ab-cdef-0123-456789abcdef", + "type": "string" + }, + "is_deleted": { + "description": "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages.", + "example": true, + "type": "boolean" + }, + "legacy_agent": { + "description": "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users.", + "example": "string", + "type": "string" + }, + "metadata": { + "description": "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "org": { + "description": "ID of the organization that owns this message (`org_...`).", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "reactions": { + "description": "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.", + "example": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "items": { + "description": "A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message.", + "example": { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + }, + "properties": { + "payload": { + "description": "Type-specific reaction data. For `\"emoji_reaction\"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `\"👍\"`).", + "example": { + "key": "value" + }, + "type": "object" + }, + "type": { + "description": "Reaction type identifier. Currently always `\"emoji_reaction\"` for emoji-based reactions.", + "example": "emoji_reaction", + "type": "string" + }, + "user": { + "description": "Public ID of the user who added the reaction (`usr_...`).", + "example": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "rendering_mode": { + "description": "Display hint for how the message should be rendered. One of `\"reply\"`, `\"direct\"`, or `\"inline\"`. `null` for user-authored messages, which are always rendered as standard replies.", + "example": "reply", + "type": "string" + }, + "replies": { + "description": "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "replies_after_cursor": { + "description": "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "replies_before_cursor": { + "description": "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.", + "example": "string", + "type": "string" + }, + "reply_count": { + "description": "Total number of direct replies to this message. Only present when explicitly requested or computed by the server.", + "example": 1, + "type": "integer" + }, + "reply_to": { + "description": "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded.", + "example": { + "acl": { + "add": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "grants": [ + { + "actions": [ + "read", + "write" + ], + "principal": "string", + "principal_type": "user" + } + ], + "remove": [ + { + "principal": "string", + "principal_type": "user" + } + ] + }, + "actors": [ + { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + } + ], + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "agent_mode": "cli", + "attachments": [ + { + "content_type": "application/json", + "description": "An example description.", + "filename": "string", + "height": 1, + "id": "string", + "image_height": 1, + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "image_url": "https://example.com", + "image_width": 1, + "media_type": "application/json", + "name": "Example Name", + "object": {}, + "title": "Example Title", + "type": "file", + "url": "https://example.com", + "variants": [ + { + "content_type": "application/json", + "created_at": "2024-01-01T00:00:00Z", + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "filename": "string", + "height": 600, + "id": "mvr_0aBcDeFgHiJkLmNoPqRsTu", + "image_source": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "updated_at": "2024-01-01T00:00:00Z", + "url": "https://example.com", + "variant_key": "original", + "width": 800 + } + ], + "version": 1, + "width": 1 + } + ], + "branched_thread": "string", + "content": "Hello, how can I help you today?", + "created_at": "2024-01-01T00:00:00Z", + "has_replies": true, + "id": "msg_0aBcDeFgHiJkLmNoPqRsTu", + "idempotency_key": "01234567-89ab-cdef-0123-456789abcdef", + "is_deleted": true, + "legacy_agent": "string", + "metadata": { + "key": "value" + }, + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "reactions": [ + { + "payload": { + "key": "value" + }, + "type": "emoji_reaction", + "user": "string" + } + ], + "rendering_mode": "reply", + "replies": [ + {} + ], + "replies_after_cursor": "string", + "replies_before_cursor": "string", + "reply_count": 1, + "reply_to": {}, + "root_message_id": "string", + "sandbox": "string", + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "string", + "type": "note", + "user": "string", + "visibility": "default" + }, + "type": "object" + }, + "root_message_id": { + "description": "ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.", + "example": "string", + "nullable": true, + "type": "string" + }, + "sandbox": { + "description": "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages.", + "example": "string", + "type": "string" + }, + "team": { + "description": "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread.", + "example": "string", + "type": "string" + }, + "type": { + "description": "Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.", + "example": "note", + "type": "string" + }, + "user": { + "description": "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents.", + "example": "string", + "type": "string" + }, + "visibility": { + "description": "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees.", + "enum": [ + "default", + "private" + ], + "example": "default", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "thread_id": { + "example": "string", + "type": "string" + } + }, + "type": "object" + } + }, + { + "description": "Broadcast thread-level events (agent updates, read state, unread counts)", + "event": "thread_event", + "payload": { + "example": { + "payload": {}, + "thread_id": "string", + "type": "string" + }, + "properties": { + "payload": { + "example": {}, + "type": "object" + }, + "thread_id": { + "example": "string", + "type": "string" + }, + "type": { + "example": "string", + "type": "string" + } + }, + "type": "object" + } + }, + { + "description": "Broadcast system-wide events", + "event": "system_event", + "payload": { + "example": { + "event": {} + }, + "properties": { + "event": { + "example": {}, + "type": "object" + } + }, + "type": "object" + } + }, + { + "description": "Broadcast when a participant (human or agent) starts or stops typing. Ephemeral; never persisted.", + "event": "typing", + "payload": { + "example": { + "actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "is_typing": true, + "thread_id": "string" + }, + "properties": { + "actor": { + "description": "The entity that authored a message, either a human user or an agent.", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "is_typing": { + "example": true, + "type": "boolean" + }, + "thread_id": { + "example": "string", + "type": "string" + } + }, + "type": "object" + } + } + ], + "x-auth": [ + "bearer" + ] + }, + { + "description": "Channel for real-time custom object collaboration.\n\nClients join `api:object:{object_id}` to receive the current object state\nand subscribe to field-level updates. Mutations are sent as key:value maps.\n", + "joins": [ + { + "description": null, + "name": "join_by_id", + "params": { + "example": { + "connection_id": "string", + "object_id": "string", + "partial_updates": true + }, + "properties": { + "connection_id": { + "example": "string", + "type": "string" + }, + "object_id": { + "example": "string", + "type": "string" + }, + "partial_updates": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "object_id" + ], + "type": "object" + }, + "pattern": "api:object:{object_id}", + "returns": { + "description": "Initial authoritative snapshot returned by a custom-object channel join.", + "example": { + "connection_id": "string", + "fields": {}, + "id": "string", + "presence": [ + {} + ], + "readonly": true + }, + "properties": { + "connection_id": { + "description": "Collision-free identifier for this browser connection.", + "example": "string", + "type": "string" + }, + "fields": { + "description": "Current materialized fields, or `null` while waiting for object creation.", + "example": {}, + "nullable": true, + "type": "object" + }, + "id": { + "description": "Custom-object ID, or `null` while a row-key subscription waits for creation.", + "example": "string", + "nullable": true, + "type": "string" + }, + "presence": { + "description": "Current ephemeral collaborator presence.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "readonly": { + "description": "Whether the current connection may only read the object.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "id", + "fields", + "readonly", + "connection_id", + "presence" + ], + "type": "object" + } + }, + { + "description": null, + "name": "join_by_row_key", + "params": { + "example": { + "connection_id": "string", + "partial_updates": true, + "row_key": "string", + "schema_type": "string" + }, + "properties": { + "connection_id": { + "example": "string", + "type": "string" + }, + "partial_updates": { + "example": true, + "type": "boolean" + }, + "row_key": { + "example": "string", + "type": "string" + }, + "schema_type": { + "example": "string", + "type": "string" + } + }, + "required": [ + "schema_type", + "row_key" + ], + "type": "object" + }, + "pattern": "api:object:{schema_type}:{row_key}", + "returns": { + "description": "Initial authoritative snapshot returned by a custom-object channel join.", + "example": { + "connection_id": "string", + "fields": {}, + "id": "string", + "presence": [ + {} + ], + "readonly": true + }, + "properties": { + "connection_id": { + "description": "Collision-free identifier for this browser connection.", + "example": "string", + "type": "string" + }, + "fields": { + "description": "Current materialized fields, or `null` while waiting for object creation.", + "example": {}, + "nullable": true, + "type": "object" + }, + "id": { + "description": "Custom-object ID, or `null` while a row-key subscription waits for creation.", + "example": "string", + "nullable": true, + "type": "string" + }, + "presence": { + "description": "Current ephemeral collaborator presence.", + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "readonly": { + "description": "Whether the current connection may only read the object.", + "example": true, + "type": "boolean" + } + }, + "required": [ + "id", + "fields", + "readonly", + "connection_id", + "presence" + ], + "type": "object" + } + } + ], + "messages": [ + { + "description": null, + "event": "update_fields", + "params": { + "example": { + "fields": {}, + "operation_id": "string" + }, + "properties": { + "fields": { + "example": {}, + "type": "object" + }, + "operation_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "fields" + ], + "type": "object" + }, + "returns": { + "description": "Response returned after updating one or more fields on a custom object. Confirms the object that was modified and the field values that were applied.", + "example": { + "fields": { + "key": "value" + }, + "id": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "operation_id": "string" + }, + "properties": { + "fields": { + "description": "The materialized object fields after the update.", + "example": { + "key": "value" + }, + "type": "object" + }, + "id": { + "description": "ID of the custom object that was updated (`cobj_...`).", + "example": "cobj_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "operation_id": { + "description": "Idempotency key acknowledged for this update.", + "example": "string", + "type": "string" + } + }, + "required": [ + "id", + "fields", + "operation_id" + ], + "type": "object" + } + }, + { + "description": null, + "event": "save", + "params": { + "properties": {}, + "type": "object" + }, + "returns": { + "description": "Acknowledges that the current custom-object document reached durable storage.", + "example": { + "version": 1 + }, + "properties": { + "version": { + "description": "Durable optimistic-concurrency version after the save.", + "example": 1, + "type": "integer" + } + }, + "required": [ + "version" + ], + "type": "object" + } + }, + { + "description": null, + "event": "presence_update", + "params": { + "example": { + "presence": {} + }, + "properties": { + "presence": { + "example": {}, + "type": "object" + } + }, + "required": [ + "presence" + ], + "type": "object" + }, + "returns": { + "description": "Acknowledges an ephemeral custom-object presence update.", + "example": { + "connection_id": "string" + }, + "properties": { + "connection_id": { + "description": "Collision-free connection identifier assigned to this browser connection.", + "example": "string", + "type": "string" + } + }, + "required": [ + "connection_id" + ], + "type": "object" + } + } + ], + "name": "ApiObjectChannel", + "pushes": [ + { + "description": null, + "event": "object_updated", + "payload": { + "example": { + "fields": {}, + "id": "string", + "operation_id": "string", + "partial": true + }, + "properties": { + "fields": { + "example": {}, + "type": "object" + }, + "id": { + "example": "string", + "type": "string" + }, + "operation_id": { + "example": "string", + "type": "string" + }, + "partial": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "id", + "fields", + "operation_id", + "partial" + ], + "type": "object" + } + }, + { + "description": null, + "event": "object_created", + "payload": { + "example": { + "connection_id": "string", + "fields": {}, + "id": "string", + "presence": [ + {} + ], + "readonly": true + }, + "properties": { + "connection_id": { + "example": "string", + "type": "string" + }, + "fields": { + "example": {}, + "type": "object" + }, + "id": { + "example": "string", + "type": "string" + }, + "presence": { + "example": [ + {} + ], + "items": { + "type": "object" + }, + "type": "array" + }, + "readonly": { + "example": true, + "type": "boolean" + } + }, + "required": [ + "id", + "fields", + "readonly", + "connection_id", + "presence" + ], + "type": "object" + } + }, + { + "description": null, + "event": "object_deleted", + "payload": { + "example": { + "id": "string" + }, + "properties": { + "id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + }, + { + "description": null, + "event": "presence_updated", + "payload": { + "example": { + "presence": {} + }, + "properties": { + "presence": { + "example": {}, + "type": "object" + } + }, + "required": [ + "presence" + ], + "type": "object" + } + }, + { + "description": null, + "event": "presence_left", + "payload": { + "example": { + "connection_id": "string" + }, + "properties": { + "connection_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "connection_id" + ], + "type": "object" + } + }, + { + "description": null, + "event": "access_revoked", + "payload": { + "example": { + "reason": "string" + }, + "properties": { + "reason": { + "example": "string", + "type": "string" + } + }, + "required": [ + "reason" + ], + "type": "object" + } + } + ], + "x-auth": [ + "bearer" + ] + }, + { + "description": "Phoenix channel for live task-record updates.\n\nClients join `api:tasks:thread:{thread_id}` to receive the thread's current\nevent-sourced tasks and subscribe to changes. The join reply carries a full\nsnapshot (`%{tasks: [...]}`), and every subsequent change lands as a\n`tasks_updated` push carrying a fresh snapshot — the same replace-wholesale\ncontract expected by task-panel clients, so clients need no\ndelta bookkeeping.\n\nChange signals originate from `ArchAstro.Tasks.Projectors.TaskProjector`,\nwhich broadcasts on `\"tasks:thread:{thread_id}\"` after each committed\nprojection. Bursts (e.g. a mirror reconcile dispatching several commands)\nare coalesced: the first signal arms a short timer and the reload happens\nonce, after the burst settles.\n", + "joins": [ + { + "description": "Join a thread's live task list", + "name": "join_thread", + "params": { + "example": { + "thread_id": "string" + }, + "properties": { + "thread_id": { + "example": "string", + "type": "string" + } + }, + "required": [ + "thread_id" + ], + "type": "object" + }, + "pattern": "api:tasks:thread:{thread_id}", + "returns": { + "type": "object" + } + } + ], + "messages": [], + "name": "ApiTasksChannel", + "pushes": [ + { + "description": "Broadcast when the thread's task records change; carries a full snapshot", + "event": "tasks_updated", + "payload": { + "example": { + "tasks": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ] + }, + "properties": { + "tasks": { + "example": [ + { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + } + ], + "items": { + "description": "A task representing a unit of work, optionally assignable to a user or agent.", + "example": { + "agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "blocked_by_count": 1, + "closed_at": "2024-01-01T00:00:00Z", + "comments_count": 1, + "created_at": "2024-01-01T00:00:00Z", + "created_by_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "created_by_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "created_by_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "current_lease": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "description": "An example description.", + "due_date": "2024-01-01T00:00:00Z", + "id": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "is_blocked": true, + "links": { + "key": "value" + }, + "metadata": { + "key": "value" + }, + "name": "Example Name", + "org": "org_0aBcDeFgHiJkLmNoPqRsTu", + "owner_actor": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "owner_agent": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "owner_user": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "parent": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "priority": 2, + "sandbox": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "status": "open", + "subtasks_count": 1, + "tags": [ + "string" + ], + "team": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "thread": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "updated_at": "2024-01-01T00:00:00Z", + "user": "usr_0aBcDeFgHiJkLmNoPqRsTu" + }, + "properties": { + "agent": { + "description": "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "blocked_by_count": { + "description": "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind.", + "example": 1, + "type": "integer" + }, + "closed_at": { + "description": "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "comments_count": { + "description": "Total number of comments posted on this task.", + "example": 1, + "type": "integer" + }, + "created_at": { + "description": "When the task was created (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by_actor": { + "description": "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "created_by_agent": { + "description": "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "created_by_user": { + "description": "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "current_lease": { + "description": "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included.", + "example": { + "expires_at": "2024-01-01T00:00:00Z", + "harness": "string", + "session_name": "Example Name" + }, + "nullable": true, + "properties": { + "expires_at": { + "description": "Server-calculated lease expiry in ISO 8601 format.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "harness": { + "description": "Bounded harness identifier for the coding session.", + "example": "string", + "type": "string" + }, + "session_name": { + "description": "Display name supplied by the coding session that holds the lease.", + "example": "Example Name", + "type": "string" + } + }, + "required": [ + "session_name", + "harness", + "expires_at" + ], + "type": "object" + }, + "description": { + "description": "Long-form description or notes for the task. `null` if no description has been provided.", + "example": "An example description.", + "type": "string" + }, + "due_date": { + "description": "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set.", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Task ID (`tsk_...`).", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "is_blocked": { + "description": "`true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read.", + "example": true, + "type": "boolean" + }, + "links": { + "description": "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "metadata": { + "description": "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.", + "example": { + "key": "value" + }, + "type": "object" + }, + "name": { + "description": "Human-readable title of the task.", + "example": "Example Name", + "type": "string" + }, + "org": { + "description": "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context.", + "example": "org_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_actor": { + "description": "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted).", + "example": { + "alias": "alice", + "id": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "name": "Example Name", + "profile_picture": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + } + }, + "properties": { + "alias": { + "description": "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured.", + "example": "alice", + "type": "string" + }, + "id": { + "description": "Composite actor identifier. Format is `\"user-\"` for human users or `\"agent-\"` for agents.", + "example": "user-usr_01j3k5m7n9p2r4s6t8v0w1x2", + "type": "string" + }, + "name": { + "description": "Display name of the actor shown in the UI. `null` if no name is set.", + "example": "Example Name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture for the actor. `null` if the actor has no profile picture.", + "example": { + "file": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "height": 600, + "media": "med_0aBcDeFgHiJkLmNoPqRsTu", + "mime_type": "application/json", + "refresh_url": "https://example.com", + "url": "https://example.com", + "width": 800 + }, + "properties": { + "file": { + "description": "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file.", + "example": "fil_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "height": { + "description": "Height of the image in pixels. `null` if not known.", + "example": 600, + "type": "integer" + }, + "media": { + "description": "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity.", + "example": "med_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "mime_type": { + "description": "MIME type of the image, e.g. `\"image/png\"` or `\"image/jpeg\"`. `null` if not known.", + "example": "application/json", + "type": "string" + }, + "refresh_url": { + "description": "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing.", + "example": "https://example.com", + "type": "string" + }, + "url": { + "description": "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires.", + "example": "https://example.com", + "type": "string" + }, + "width": { + "description": "Width of the image in pixels. `null` if not known.", + "example": 800, + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "owner_agent": { + "description": "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted.", + "example": "agi_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "owner_user": { + "description": "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "parent": { + "description": "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level.", + "example": "tsk_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "priority": { + "description": "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set.", + "example": 2, + "type": "integer" + }, + "sandbox": { + "description": "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment.", + "example": "dsb_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "status": { + "description": "Current status of the task. One of `\"open\"`, `\"in_progress\"`, or `\"done\"`.", + "example": "open", + "type": "string" + }, + "subtasks_count": { + "description": "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.", + "example": 1, + "type": "integer" + }, + "tags": { + "description": "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.", + "example": [ + "string" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "team": { + "description": "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team.", + "example": "tem_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "thread": { + "description": "ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread.", + "example": "thr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + }, + "updated_at": { + "description": "When the task was last modified (ISO 8601).", + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team.", + "example": "usr_0aBcDeFgHiJkLmNoPqRsTu", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + } + } + ], + "x-auth": [ + "bearer" + ] + } + ], + "x-token-flows": { + "login": { + "constructor": "with_credentials", + "description": "Create a client by logging in with email/password", + "operation_name": "login", + "operation_tag": "auth", + "requires": [ + "publishable_key" + ] + }, + "refresh": { + "description": "Refresh an expired access token", + "operation_name": "refresh", + "operation_tag": "auth" + } + } +} \ No newline at end of file diff --git a/src/blocking.rs b/src/blocking.rs new file mode 100644 index 0000000..96e61d5 --- /dev/null +++ b/src/blocking.rs @@ -0,0 +1,19 @@ +//! Blocking bridge for generated `_blocking` methods. + +use std::future::Future; + +use crate::{Error, Result}; + +/// Execute one SDK future from synchronous code. +pub fn block_on(future: impl Future>) -> Result { + if tokio::runtime::Handle::try_current().is_ok() { + return Err(Error::Configuration( + "blocking SDK methods cannot run inside an async Tokio runtime".into(), + )); + } + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .map_err(|error| Error::Configuration(error.to_string()))? + .block_on(future) +} diff --git a/src/channel.rs b/src/channel.rs new file mode 100644 index 0000000..12f03d5 --- /dev/null +++ b/src/channel.rs @@ -0,0 +1,851 @@ +use std::collections::HashMap; +use std::pin::Pin; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::task::{Context, Poll}; +use std::time::Duration; + +use futures_core::Stream; +use futures_util::{SinkExt, StreamExt}; +use serde::de::DeserializeOwned; +use serde_json::{Value, json}; +use tokio::sync::{Mutex, broadcast, oneshot}; +use tokio_stream::wrappers::BroadcastStream; +use tokio_tungstenite::tungstenite::Message; + +use crate::{ChannelError, Error, Result}; + +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_HEARTBEAT: Duration = Duration::from_secs(30); +const BUFFER_CAPACITY: usize = 32; +const DEFAULT_BACKOFF: &[Duration] = &[ + Duration::from_millis(10), + Duration::from_millis(50), + Duration::from_millis(100), + Duration::from_millis(150), + Duration::from_millis(200), + Duration::from_millis(250), + Duration::from_millis(500), + Duration::from_secs(1), + Duration::from_secs(2), +]; + +type Ws = + tokio_tungstenite::WebSocketStream>; +type Writer = futures_util::stream::SplitSink; +type Reader = futures_util::stream::SplitStream; +type EventKey = (String, String); + +/// Phoenix channel lifecycle state. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ChannelState { + /// Not joined. + Closed, + /// Join request is in flight. + Joining, + /// Joined and ready for pushes. + Joined, + /// Leave request is in flight. + Leaving, + /// Join or transport failed. + Errored, +} + +/// Socket lifecycle notification. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SocketEvent { + /// The transport connected or reconnected. + Open, + /// The transport closed. + Close { + /// WebSocket close code, when supplied. + code: Option, + /// WebSocket close reason. + reason: String, + }, + /// A connection attempt failed. + Error(String), +} + +/// Configures and connects a Phoenix socket. +pub struct SocketBuilder { + url: String, + params: Vec<(String, String)>, + timeout: Duration, + heartbeat: Duration, + reconnect_backoff: Vec, + auto_reconnect: bool, +} + +impl SocketBuilder { + /// Create a builder for a Phoenix WebSocket URL. + pub fn new(url: impl Into) -> Self { + Self { + url: url.into(), + params: Vec::new(), + timeout: DEFAULT_TIMEOUT, + heartbeat: DEFAULT_HEARTBEAT, + reconnect_backoff: DEFAULT_BACKOFF.to_vec(), + auto_reconnect: true, + } + } + + /// Add a socket connect parameter. + pub fn param(mut self, key: impl Into, value: impl Into) -> Self { + self.params.push((key.into(), value.into())); + self + } + + /// Set join/push/leave timeout. + pub fn timeout(mut self, value: Duration) -> Self { + self.timeout = value; + self + } + + /// Set Phoenix heartbeat interval. + pub fn heartbeat(mut self, value: Duration) -> Self { + self.heartbeat = value; + self + } + + /// Enable or disable automatic transport reconnect and channel rejoin. + pub fn auto_reconnect(mut self, value: bool) -> Self { + self.auto_reconnect = value; + self + } + + /// Replace the reconnect delay schedule. + pub fn reconnect_backoff(mut self, value: impl IntoIterator) -> Self { + self.reconnect_backoff = value.into_iter().collect(); + self + } + + /// Connect and start receive, reconnect, and heartbeat tasks. + pub async fn connect(self) -> Result { + let mut url = url::Url::parse(&self.url)?; + { + let mut query = url.query_pairs_mut(); + query.append_pair("vsn", "2.0.0"); + for (key, value) in self.params { + query.append_pair(&key, &value); + } + } + let (writer, reader) = connect_once(url.as_str()).await?; + let (socket_events, _) = broadcast::channel(BUFFER_CAPACITY); + let inner = Arc::new(SocketInner { + url: url.into(), + writer: Mutex::new(Some(writer)), + pending: Mutex::new(HashMap::new()), + events: Mutex::new(HashMap::new()), + buffered: Mutex::new(HashMap::new()), + channels: std::sync::Mutex::new(HashMap::new()), + socket_events, + refs: AtomicU64::new(0), + connected: AtomicBool::new(true), + closing: AtomicBool::new(false), + reconnecting: AtomicBool::new(false), + timeout: self.timeout, + heartbeat: self.heartbeat, + reconnect_backoff: if self.reconnect_backoff.is_empty() { + DEFAULT_BACKOFF.to_vec() + } else { + self.reconnect_backoff + }, + auto_reconnect: self.auto_reconnect, + }); + spawn_reader(Arc::clone(&inner), reader); + tokio::spawn(heartbeat_loop(Arc::clone(&inner))); + let _ = inner.socket_events.send(SocketEvent::Open); + Ok(Socket { inner }) + } +} + +struct SocketInner { + url: String, + writer: Mutex>, + pending: Mutex>>>, + events: Mutex>>, + buffered: Mutex>>, + channels: std::sync::Mutex>>, + socket_events: broadcast::Sender, + refs: AtomicU64, + connected: AtomicBool, + closing: AtomicBool, + reconnecting: AtomicBool, + timeout: Duration, + heartbeat: Duration, + reconnect_backoff: Vec, + auto_reconnect: bool, +} + +/// A connected Phoenix socket. Clone it freely across tasks. +#[derive(Clone)] +pub struct Socket { + inner: Arc, +} + +impl Socket { + /// Return the existing channel for a topic or create one. + pub fn channel(&self, topic: impl Into) -> Channel { + let topic = topic.into(); + let mut channels = self + .inner + .channels + .lock() + .expect("channel registry poisoned"); + if let Some(existing) = channels.get(&topic).and_then(std::sync::Weak::upgrade) { + return Channel { inner: existing }; + } + let inner = Arc::new(ChannelInner { + socket: self.clone(), + topic: topic.clone(), + state: Mutex::new(ChannelState::Closed), + join_ref: Mutex::new(None), + join_payload: Mutex::new(json!({})), + join_gate: Mutex::new(()), + desired_join: AtomicBool::new(false), + buffered_pushes: Mutex::new(Vec::new()), + }); + channels.insert(topic, Arc::downgrade(&inner)); + Channel { inner } + } + + /// Whether the underlying WebSocket is currently open. + pub fn is_connected(&self) -> bool { + self.inner.connected.load(Ordering::Acquire) + } + + /// Subscribe to socket open, close, and connection-error events. + pub fn events(&self) -> SocketEventStream { + SocketEventStream { + inner: BroadcastStream::new(self.inner.socket_events.subscribe()), + } + } + + /// Gracefully close the WebSocket and disable reconnection. + pub async fn close(&self) -> Result<()> { + self.inner.closing.store(true, Ordering::Release); + self.inner.connected.store(false, Ordering::Release); + if let Some(mut writer) = self.inner.writer.lock().await.take() { + writer.close().await?; + } + Ok(()) + } + + fn next_ref(&self) -> String { + self.inner + .refs + .fetch_add(1, Ordering::Relaxed) + .wrapping_add(1) + .to_string() + } + + async fn request( + &self, + join_ref: Option<&str>, + topic: &str, + event: &str, + payload: Value, + ) -> Result<(String, Value)> { + if !self.is_connected() { + return Err(Error::Closed); + } + let reference = self.next_ref(); + let frame = json!([join_ref, reference, topic, event, payload]); + let (sender, receiver) = oneshot::channel(); + self.inner + .pending + .lock() + .await + .insert(reference.clone(), sender); + let send_result = { + let mut writer = self.inner.writer.lock().await; + match writer.as_mut() { + Some(writer) => writer.send(Message::Text(frame.to_string().into())).await, + None => { + self.inner.pending.lock().await.remove(&reference); + return Err(Error::Closed); + } + } + }; + if let Err(error) = send_result { + self.inner.pending.lock().await.remove(&reference); + return Err(error.into()); + } + let response = match tokio::time::timeout(self.inner.timeout, receiver).await { + Ok(response) => response.map_err(|_| Error::Closed)??, + Err(_) => { + self.inner.pending.lock().await.remove(&reference); + return Err(Error::Timeout); + } + }; + Ok((reference, response)) + } + + async fn subscribe( + &self, + topic: &str, + event: &str, + ) -> ChannelEventStream { + let key = (topic.to_owned(), event.to_owned()); + let sender = { + let mut events = self.inner.events.lock().await; + events + .entry(key.clone()) + .or_insert_with(|| broadcast::channel(BUFFER_CAPACITY).0) + .clone() + }; + let receiver = sender.subscribe(); + if let Some(values) = self.inner.buffered.lock().await.remove(&key) { + for value in values { + let _ = sender.send(value); + } + } + ChannelEventStream { + inner: BroadcastStream::new(receiver), + marker: std::marker::PhantomData, + } + } +} + +struct BufferedPush { + reference: String, + event: String, + payload: Value, + sender: oneshot::Sender>, +} + +struct ChannelInner { + socket: Socket, + topic: String, + state: Mutex, + join_ref: Mutex>, + join_payload: Mutex, + join_gate: Mutex<()>, + desired_join: AtomicBool, + buffered_pushes: Mutex>, +} + +/// A joined Phoenix channel. +#[derive(Clone)] +pub struct Channel { + inner: Arc, +} + +impl Channel { + /// Topic string. + pub fn topic(&self) -> &str { + &self.inner.topic + } + + /// Current local lifecycle state. + pub async fn state(&self) -> ChannelState { + *self.inner.state.lock().await + } + + /// Join and return the server response payload. + pub async fn join(&self, payload: Value) -> Result { + *self.inner.join_payload.lock().await = payload; + self.inner.desired_join.store(true, Ordering::Release); + self.join_saved().await + } + + async fn join_saved(&self) -> Result { + let _gate = self.inner.join_gate.lock().await; + if *self.inner.state.lock().await == ChannelState::Joined { + return Ok(json!({})); + } + *self.inner.state.lock().await = ChannelState::Joining; + let payload = self.inner.join_payload.lock().await.clone(); + let result = self + .inner + .socket + .request(None, &self.inner.topic, "phx_join", payload) + .await; + let (reference, envelope) = match result { + Ok(value) => value, + Err(error) => { + *self.inner.state.lock().await = ChannelState::Errored; + return Err(error); + } + }; + match reply(&self.inner.topic, "join", &envelope) { + Ok(value) => { + *self.inner.join_ref.lock().await = Some(reference); + *self.inner.state.lock().await = ChannelState::Joined; + self.flush_pushes().await; + Ok(value) + } + Err(error) => { + *self.inner.state.lock().await = ChannelState::Errored; + Err(error) + } + } + } + + /// Push an event and return its reply response. + /// + /// Pushes made while a desired channel is reconnecting are buffered until + /// its join succeeds or the normal operation timeout expires. + pub async fn push(&self, event: &str, payload: Value) -> Result { + if *self.inner.state.lock().await != ChannelState::Joined { + if !self.inner.desired_join.load(Ordering::Acquire) { + return Err(channel_error( + &self.inner.topic, + event, + "channel is not joined", + )); + } + let (sender, receiver) = oneshot::channel(); + let reference = self.inner.socket.next_ref(); + self.inner.buffered_pushes.lock().await.push(BufferedPush { + reference: reference.clone(), + event: event.to_owned(), + payload, + sender, + }); + return match tokio::time::timeout(self.inner.socket.inner.timeout, receiver).await { + Ok(result) => result.map_err(|_| Error::Closed)?, + Err(_) => { + self.inner + .buffered_pushes + .lock() + .await + .retain(|push| push.reference != reference); + Err(Error::Timeout) + } + }; + } + self.push_now(event, payload).await + } + + async fn push_now(&self, event: &str, payload: Value) -> Result { + let join_ref = self.inner.join_ref.lock().await.clone(); + let (_, envelope) = self + .inner + .socket + .request(join_ref.as_deref(), &self.inner.topic, event, payload) + .await?; + reply(&self.inner.topic, event, &envelope) + } + + async fn flush_pushes(&self) { + let pushes = std::mem::take(&mut *self.inner.buffered_pushes.lock().await); + for push in pushes { + if push.sender.is_closed() { + continue; + } + let channel = self.clone(); + tokio::spawn(async move { + let result = channel.push_now(&push.event, push.payload).await; + let _ = push.sender.send(result); + }); + } + } + + /// Leave the topic. A timed-out leave is treated as successful because the + /// server tears down the subscription regardless. + pub async fn leave(&self) -> Result<()> { + self.inner.desired_join.store(false, Ordering::Release); + if *self.inner.state.lock().await == ChannelState::Closed { + return Ok(()); + } + *self.inner.state.lock().await = ChannelState::Leaving; + let join_ref = self.inner.join_ref.lock().await.clone(); + let result = self + .inner + .socket + .request( + join_ref.as_deref(), + &self.inner.topic, + "phx_leave", + json!({}), + ) + .await; + *self.inner.join_ref.lock().await = None; + *self.inner.state.lock().await = ChannelState::Closed; + self.inner + .socket + .inner + .channels + .lock() + .expect("channel registry poisoned") + .remove(&self.inner.topic); + match result { + Ok(_) | Err(Error::Timeout | Error::Closed) => Ok(()), + Err(error) => Err(error), + } + } + + /// Subscribe to a typed server push. + pub fn subscribe( + &self, + event: &str, + ) -> ChannelEventStream { + ChannelEventStream::pending( + self.inner.socket.clone(), + self.inner.topic.clone(), + event.to_owned(), + ) + } +} + +/// Stream of socket lifecycle events. +pub struct SocketEventStream { + inner: BroadcastStream, +} + +impl Stream for SocketEventStream { + type Item = SocketEvent; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + loop { + match Pin::new(&mut self.inner).poll_next(cx) { + Poll::Ready(Some(Ok(event))) => return Poll::Ready(Some(event)), + Poll::Ready(Some(Err(_))) => continue, + Poll::Ready(None) => return Poll::Ready(None), + Poll::Pending => return Poll::Pending, + } + } + } +} + +/// Stream of typed Phoenix server-push payloads. +pub struct ChannelEventStream { + inner: BroadcastStream, + marker: std::marker::PhantomData, +} + +impl ChannelEventStream { + fn pending(socket: Socket, topic: String, event: String) -> Self { + let (forward, forwarded) = broadcast::channel(BUFFER_CAPACITY); + tokio::spawn(async move { + let mut source = socket.subscribe::(&topic, &event).await; + while let Some(value) = source.next().await { + if let Ok(value) = value { + let _ = forward.send(value); + } + } + }); + Self { + inner: BroadcastStream::new(forwarded), + marker: std::marker::PhantomData, + } + } +} + +impl Stream for ChannelEventStream { + type Item = Result; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match Pin::new(&mut self.inner).poll_next(cx) { + Poll::Ready(Some(Ok(value))) => { + Poll::Ready(Some(serde_json::from_value(value).map_err(Error::from))) + } + Poll::Ready(Some(Err(error))) => Poll::Ready(Some(Err(Error::Channel(ChannelError { + operation: "receive".into(), + topic: String::new(), + reason: error.to_string(), + payload: None, + })))), + Poll::Ready(None) => Poll::Ready(None), + Poll::Pending => Poll::Pending, + } + } +} + +fn reply(topic: &str, operation: &str, envelope: &Value) -> Result { + let status = envelope + .get("status") + .and_then(Value::as_str) + .unwrap_or("error"); + let response = envelope.get("response").cloned().unwrap_or(Value::Null); + if status == "ok" { + Ok(response) + } else { + Err(ChannelError { + operation: operation.to_owned(), + topic: topic.to_owned(), + reason: "server rejected the operation".into(), + payload: Some(response), + } + .into()) + } +} + +fn channel_error(topic: &str, operation: &str, reason: &str) -> Error { + ChannelError { + operation: operation.to_owned(), + topic: topic.to_owned(), + reason: reason.to_owned(), + payload: None, + } + .into() +} + +async fn connect_once(url: &str) -> Result<(Writer, Reader)> { + let (stream, _) = tokio_tungstenite::connect_async(url).await?; + Ok(stream.split()) +} + +fn spawn_reader(inner: Arc, reader: Reader) { + tokio::spawn(async move { + read_loop(Arc::clone(&inner), reader).await; + handle_disconnect(Arc::clone(&inner)).await; + schedule_reconnect(inner); + }); +} + +async fn read_loop(inner: Arc, mut reader: Reader) { + let mut close = (None, String::new()); + while let Some(message) = reader.next().await { + let message = match message { + Ok(value) => value, + Err(error) => { + let _ = inner + .socket_events + .send(SocketEvent::Error(error.to_string())); + break; + } + }; + if let Message::Close(frame) = message { + if let Some(frame) = frame { + close = (Some(frame.code.into()), frame.reason.to_string()); + } + break; + } + let Message::Text(text) = message else { + continue; + }; + let Ok(Value::Array(frame)) = serde_json::from_str::(&text) else { + continue; + }; + if frame.len() != 5 { + continue; + } + let reference = frame[1].as_str().unwrap_or_default(); + let topic = frame[2].as_str().unwrap_or_default().to_owned(); + let event = frame[3].as_str().unwrap_or_default().to_owned(); + let payload = frame[4].clone(); + if event == "phx_reply" && !reference.is_empty() { + if let Some(sender) = inner.pending.lock().await.remove(reference) { + let _ = sender.send(Ok(payload)); + } + continue; + } + if let Some(channel) = channel_for(&inner, &topic) { + if !join_ref_matches(frame[0].as_str(), channel.join_ref.lock().await.as_deref()) { + continue; + } + } + if event == "phx_error" { + if let Some(channel) = channel_for(&inner, &topic) { + *channel.state.lock().await = ChannelState::Errored; + } + } else if event == "phx_close" { + if let Some(channel) = channel_for(&inner, &topic) { + channel.desired_join.store(false, Ordering::Release); + *channel.state.lock().await = ChannelState::Closed; + } + } + let key = (topic, event); + if let Some(sender) = inner.events.lock().await.get(&key).cloned() { + let _ = sender.send(payload); + } else { + let mut buffered = inner.buffered.lock().await; + let values = buffered.entry(key).or_default(); + if values.len() == BUFFER_CAPACITY { + values.remove(0); + } + values.push(payload); + } + } + let _ = inner.socket_events.send(SocketEvent::Close { + code: close.0, + reason: close.1, + }); +} + +async fn handle_disconnect(inner: Arc) { + if !inner.connected.swap(false, Ordering::AcqRel) { + return; + } + inner.writer.lock().await.take(); + let pending = std::mem::take(&mut *inner.pending.lock().await); + for (_, sender) in pending { + let _ = sender.send(Err(Error::Closed)); + } + let channels = live_channels(&inner); + for channel in channels { + let state = *channel.state.lock().await; + if state != ChannelState::Closed && state != ChannelState::Leaving { + *channel.state.lock().await = ChannelState::Errored; + *channel.join_ref.lock().await = None; + } + } +} + +fn schedule_reconnect(inner: Arc) { + if inner.closing.load(Ordering::Acquire) + || !inner.auto_reconnect + || inner.reconnecting.swap(true, Ordering::AcqRel) + { + return; + } + tokio::spawn(async move { + let mut attempt = 0_usize; + loop { + let delay = reconnect_delay(&inner.reconnect_backoff, attempt); + attempt = attempt.saturating_add(1); + tokio::time::sleep(delay).await; + if inner.closing.load(Ordering::Acquire) { + break; + } + match connect_once(&inner.url).await { + Ok((writer, reader)) => { + *inner.writer.lock().await = Some(writer); + inner.connected.store(true, Ordering::Release); + inner.reconnecting.store(false, Ordering::Release); + spawn_reader(Arc::clone(&inner), reader); + let _ = inner.socket_events.send(SocketEvent::Open); + rejoin_channels(&inner).await; + return; + } + Err(error) => { + let _ = inner + .socket_events + .send(SocketEvent::Error(error.to_string())); + } + } + } + inner.reconnecting.store(false, Ordering::Release); + }); +} + +fn join_ref_matches(frame: Option<&str>, current: Option<&str>) -> bool { + frame.is_none() || frame == current +} + +fn reconnect_delay(schedule: &[Duration], attempt: usize) -> Duration { + schedule[attempt.min(schedule.len().saturating_sub(1))] +} + +async fn rejoin_channels(inner: &Arc) { + for channel in live_channels(inner) { + if channel.desired_join.load(Ordering::Acquire) { + let channel = Channel { inner: channel }; + let _ = channel.join_saved().await; + } + } +} + +fn channel_for(inner: &SocketInner, topic: &str) -> Option> { + inner + .channels + .lock() + .expect("channel registry poisoned") + .get(topic) + .and_then(std::sync::Weak::upgrade) +} + +fn live_channels(inner: &SocketInner) -> Vec> { + let mut channels = inner.channels.lock().expect("channel registry poisoned"); + channels.retain(|_, channel| channel.strong_count() > 0); + channels + .values() + .filter_map(std::sync::Weak::upgrade) + .collect() +} + +async fn heartbeat_loop(inner: Arc) { + let mut ticker = tokio::time::interval(inner.heartbeat); + ticker.tick().await; + loop { + ticker.tick().await; + if inner.closing.load(Ordering::Acquire) { + return; + } + if !inner.connected.load(Ordering::Acquire) { + continue; + } + let socket = Socket { + inner: Arc::clone(&inner), + }; + if socket + .request(None, "phoenix", "heartbeat", json!({})) + .await + .is_err() + { + if let Some(mut writer) = inner.writer.lock().await.take() { + let _ = writer.close().await; + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use tokio::net::TcpListener; + use tokio::task::JoinHandle; + use tokio_tungstenite::accept_async; + + async fn silent_socket(timeout: Duration) -> (Socket, JoinHandle<()>) { + let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); + let address = listener.local_addr().expect("local address"); + let server = tokio::spawn(async move { + let (stream, _) = listener.accept().await.expect("accept"); + let mut websocket = accept_async(stream).await.expect("websocket handshake"); + while websocket.next().await.is_some() {} + }); + let socket = SocketBuilder::new(format!("ws://{address}/socket/api/websocket")) + .timeout(timeout) + .heartbeat(Duration::from_secs(60)) + .auto_reconnect(false) + .connect() + .await + .expect("connect"); + (socket, server) + } + + #[test] + fn stale_join_refs_are_rejected_after_rejoin() { + assert!(join_ref_matches(None, Some("new"))); + assert!(join_ref_matches(Some("new"), Some("new"))); + assert!(!join_ref_matches(Some("old"), Some("new"))); + assert!(!join_ref_matches(Some("old"), None)); + } + + #[test] + fn reconnect_backoff_clamps_to_the_last_delay() { + let schedule = [Duration::from_millis(10), Duration::from_secs(2)]; + assert_eq!(reconnect_delay(&schedule, 0), schedule[0]); + assert_eq!(reconnect_delay(&schedule, 1), schedule[1]); + assert_eq!(reconnect_delay(&schedule, 99), schedule[1]); + } + + #[tokio::test] + async fn request_timeout_removes_pending_reply() { + let (socket, server) = silent_socket(Duration::from_millis(20)).await; + let result = socket.request(None, "topic", "event", json!({})).await; + assert!(matches!(result, Err(Error::Timeout))); + assert!(socket.inner.pending.lock().await.is_empty()); + socket.close().await.expect("close"); + server.await.expect("server task"); + } + + #[tokio::test] + async fn buffered_push_timeout_removes_the_queued_operation() { + let (socket, server) = silent_socket(Duration::from_millis(20)).await; + let channel = socket.channel("topic"); + channel.inner.desired_join.store(true, Ordering::Release); + *channel.inner.state.lock().await = ChannelState::Errored; + + let result = channel.push("save", json!({})).await; + assert!(matches!(result, Err(Error::Timeout))); + assert!(channel.inner.buffered_pushes.lock().await.is_empty()); + + socket.close().await.expect("close"); + server.await.expect("server task"); + } +} diff --git a/src/client.rs b/src/client.rs new file mode 100644 index 0000000..c000f19 --- /dev/null +++ b/src/client.rs @@ -0,0 +1,291 @@ +use std::collections::BTreeMap; +use std::sync::Arc; + +use tokio::sync::{Mutex, RwLock}; + +use crate::generated::{Auth, V1}; +use crate::{AppSession, Error, RequestBuilder, Result, SessionStore, SocketBuilder}; + +const DEFAULT_BASE_URL: &str = "https://platform.archastro.ai"; + +#[derive(Debug, Clone, Default)] +pub(crate) struct Session { + pub access_token: Option, + pub refresh_token: Option, + pub refresh_path: Option, + pub access_token_expires_at: Option, + pub user: Option, + pub generation: u64, +} + +pub(crate) struct ClientInner { + pub base_url: String, + pub http: reqwest::Client, + pub headers: BTreeMap, + pub session: RwLock, + pub refresh_gate: Mutex<()>, + pub session_store: Option>, +} + +/// Cloneable asynchronous ArchAstro client. +#[derive(Clone)] +pub struct Client(pub(crate) Arc); + +/// Builder for [`Client`]. +pub struct ClientBuilder { + base_url: String, + http: Option, + headers: BTreeMap, + access_token: Option, + session_store: Option>, +} + +impl Default for ClientBuilder { + fn default() -> Self { + Self { + base_url: DEFAULT_BASE_URL.to_owned(), + http: None, + headers: BTreeMap::new(), + access_token: None, + session_store: None, + } + } +} + +impl ClientBuilder { + /// Override the API origin (primarily for private deployments and tests). + pub fn base_url(mut self, value: impl Into) -> Self { + self.base_url = value.into().trim_end_matches('/').to_owned(); + self + } + + /// Use a preconfigured Reqwest client. + pub fn http_client(mut self, value: reqwest::Client) -> Self { + self.http = Some(value); + self + } + + /// Add a default request header. + pub fn header(mut self, name: impl Into, value: impl Into) -> Self { + self.headers.insert(name.into(), value.into()); + self + } + + /// Authenticate with a secret API key. + pub fn secret_key(self, value: impl Into) -> Self { + self.header("x-archastro-api-key", value) + } + + /// Configure the publishable key used by app-user auth flows. + pub fn publishable_key(self, value: impl Into) -> Self { + self.header("x-archastro-api-key", value) + } + + /// Use an existing bearer/system-user token. + pub fn access_token(mut self, value: impl Into) -> Self { + self.access_token = Some(value.into()); + self + } + + /// Persist app-user sessions and refresh-token rotations in this store. + pub fn session_store(mut self, value: Arc) -> Self { + self.session_store = Some(value); + self + } + + /// Build a client and validate its base URL. + pub fn build(self) -> Result { + let _ = url::Url::parse(&self.base_url)?; + let http = match self.http { + Some(client) => client, + None => reqwest::Client::builder() + .connect_timeout(std::time::Duration::from_secs(10)) + .tcp_keepalive(std::time::Duration::from_secs(30)) + .build()?, + }; + Ok(Client(Arc::new(ClientInner { + base_url: self.base_url, + http, + headers: self.headers, + session: RwLock::new(Session { + access_token: self.access_token, + ..Session::default() + }), + refresh_gate: Mutex::new(()), + session_store: self.session_store, + }))) + } +} + +impl Client { + /// Start building a client. + pub fn builder() -> ClientBuilder { + ClientBuilder::default() + } + + /// Build a client with defaults and no authentication. + pub fn new() -> Result { + Self::builder().build() + } + + /// Version 1 API namespace. + pub fn v1(&self) -> V1 { + V1 { + client: self.clone(), + } + } + + /// Authentication endpoints. + pub fn auth(&self) -> Auth { + Auth { + client: self.clone(), + } + } + + /// Start a typed HTTP request used by generated resources. + pub fn request(&self, method: reqwest::Method, path: &str) -> RequestBuilder { + RequestBuilder::new(self.clone(), method, path) + } + + /// Build a Phoenix socket authenticated from the client's current session. + pub async fn socket(&self) -> Result { + let session = self.0.session.read().await; + let token = session.access_token.clone().ok_or_else(|| { + Error::Configuration("a bearer token is required for channels".into()) + })?; + let mut builder = + SocketBuilder::new(websocket_url(&self.0.base_url)?).param("token", token); + if let Some(key) = self + .0 + .headers + .iter() + .find(|(key, _)| key.eq_ignore_ascii_case("x-archastro-api-key")) + .map(|(_, value)| value) + { + builder = builder.param("api_key", key.clone()); + } + Ok(builder) + } + + /// Replace the access/refresh token pair used by this client. + pub async fn install_session( + &self, + access_token: String, + refresh_token: Option, + refresh_path: &str, + ) { + let mut session = self.0.session.write().await; + session.access_token = Some(access_token); + session.refresh_token = refresh_token; + session.refresh_path = Some(refresh_path.to_owned()); + session.generation = session.generation.wrapping_add(1); + } + + /// Install and persist a complete app-user session. + pub async fn install_app_session(&self, value: AppSession) -> Result<()> { + { + let mut session = self.0.session.write().await; + session.access_token = Some(value.access_token.clone()); + session.refresh_token = value.refresh_token.clone(); + session.refresh_path = Some("/api/v1/auth/refresh".to_owned()); + session.access_token_expires_at = value.access_token_expires_at; + session.user.clone_from(&value.user); + session.generation = session.generation.wrapping_add(1); + } + if let Some(store) = &self.0.session_store { + store + .save(&value) + .await + .map_err(|error| Error::SessionStorage(error.to_string()))?; + } + Ok(()) + } + + /// Restore an app-user session from the configured store. + /// + /// A session without a refresh token is cleared because it cannot renew. + pub async fn restore_session(&self) -> Result> { + let Some(store) = &self.0.session_store else { + return Err(Error::Configuration( + "no session store is configured".into(), + )); + }; + let Some(value) = store + .load() + .await + .map_err(|error| Error::SessionStorage(error.to_string()))? + else { + return Ok(None); + }; + if value.refresh_token.is_none() { + store + .clear() + .await + .map_err(|error| Error::SessionStorage(error.to_string()))?; + return Ok(None); + } + self.install_app_session(value.clone()).await?; + Ok(Some(value)) + } + + /// Return the current app-user session, including refresh credentials. + /// + /// Treat this value as sensitive and persist it only in secure storage. + pub async fn app_session(&self) -> Option { + let session = self.0.session.read().await; + Some(AppSession { + access_token: session.access_token.clone()?, + refresh_token: session.refresh_token.clone(), + access_token_expires_at: session.access_token_expires_at, + user: session.user.clone(), + }) + } + + /// Clear the in-memory and persisted app-user session. + pub async fn sign_out(&self) -> Result<()> { + { + let mut session = self.0.session.write().await; + *session = Session { + generation: session.generation.wrapping_add(1), + ..Session::default() + }; + } + if let Some(store) = &self.0.session_store { + store + .clear() + .await + .map_err(|error| Error::SessionStorage(error.to_string()))?; + } + Ok(()) + } + + /// Return the current bearer token without exposing refresh credentials. + pub async fn access_token(&self) -> Option { + self.0.session.read().await.access_token.clone() + } +} + +fn websocket_url(base_url: &str) -> Result { + let mut url = url::Url::parse(base_url)?; + url.set_scheme(if url.scheme() == "https" { "wss" } else { "ws" }) + .map_err(|()| Error::Configuration("unsupported base URL scheme".into()))?; + url.set_path("/socket/api/websocket"); + Ok(url.to_string()) +} + +#[cfg(test)] +mod tests { + use super::websocket_url; + + #[test] + fn websocket_url_uses_the_platform_channel_endpoint() { + assert_eq!( + websocket_url("https://platform.archastro.ai/api").expect("valid URL"), + "wss://platform.archastro.ai/socket/api/websocket" + ); + assert_eq!( + websocket_url("http://localhost:4005").expect("valid URL"), + "ws://localhost:4005/socket/api/websocket" + ); + } +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..aa8a4c1 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,87 @@ +use serde_json::Value; + +/// Result type used throughout the SDK. +pub type Result = std::result::Result; + +/// A structured non-success response from the ArchAstro API. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ApiError { + /// HTTP status code. + pub status: u16, + /// Stable machine-readable error code, when supplied. + pub code: Option, + /// Human-readable message. + pub message: String, + /// Full decoded response body. + pub body: Value, +} + +impl std::fmt::Display for ApiError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "ArchAstro API returned HTTP {}: {}", + self.status, self.message + ) + } +} + +impl std::error::Error for ApiError {} + +/// A Phoenix channel lifecycle or protocol failure. +#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)] +#[error("channel {operation} on {topic:?} failed: {reason}")] +pub struct ChannelError { + /// Operation being attempted. + pub operation: String, + /// Phoenix topic. + pub topic: String, + /// Failure description. + pub reason: String, + /// Rejection payload, when supplied. + pub payload: Option, +} + +/// Every error surfaced by the SDK. +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// Structured API error. + #[error(transparent)] + Api(#[from] ApiError), + /// HTTP transport error. + #[error(transparent)] + Http(#[from] reqwest::Error), + /// JSON codec error. + #[error(transparent)] + Json(#[from] serde_json::Error), + /// Query-string codec error. + #[error(transparent)] + Query(#[from] serde_urlencoded::ser::Error), + /// URL parse error. + #[error(transparent)] + Url(#[from] url::ParseError), + /// WebSocket transport error. + #[error(transparent)] + WebSocket(#[from] tokio_tungstenite::tungstenite::Error), + /// Phoenix channel error. + #[error(transparent)] + Channel(#[from] ChannelError), + /// A generated SSE stream received an event absent from its contract. + #[error("unknown SSE event {0:?}")] + UnknownSseEvent(String), + /// An SSE transport or protocol error. + #[error("SSE stream failed: {0}")] + Sse(String), + /// Invalid SDK configuration. + #[error("invalid SDK configuration: {0}")] + Configuration(String), + /// Durable app-session storage failed. + #[error("session storage failed: {0}")] + SessionStorage(String), + /// A request timed out. + #[error("operation timed out")] + Timeout, + /// A background connection task stopped unexpectedly. + #[error("connection closed")] + Closed, +} diff --git a/src/generated/auth.rs b/src/generated/auth.rs new file mode 100644 index 0000000..bd9f87b --- /dev/null +++ b/src/generated/auth.rs @@ -0,0 +1,392 @@ +// Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License. +// This file is auto-generated by @archastro/sdk-generator. Do not edit. +// Content hash: 17fec9a34eb5 + +use crate::generated::types::*; +use crate::{Client, Result}; +use reqwest::Method; +use serde::{Deserialize, Serialize}; + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AuthAllowedAuthMethodsResponseDataItem { + /// One-sentence user-facing explanation of how this auth method works, suitable for display in an auth selection UI. + pub description: String, + /// Short user-facing label suitable for buttons or list items, e.g. `"Password"` or `"Magic Link"`. + pub name: String, + /// Stable machine-readable identifier for this auth method, e.g. `"password"` or `"magic_link"`. Use this value when enabling or referencing auth methods programmatically. + pub slug: String, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AuthAllowedAuthMethodsResponse { + /// Ordered array of supported auth method objects, each with a stable slug, display name, and description. + pub data: Vec, +} + +/// Authenticates a user with an email address and password and returns a short-lived +/// access token, a refresh token, and the authenticated user object. Use the refresh +/// token with the `/auth/refresh` endpoint to obtain new access tokens without +/// re-authenticating. +/// +/// Password login must be enabled for the app; apps that have disabled password +/// authentication return HTTP 403. Requests are rate-limited per IP (10 per minute) +/// and per email-IP pair (5 per minute) — exceeding either limit returns HTTP 429. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AuthLoginInput { + /// Email address of the user to authenticate. + pub email: String, + /// Password for the account associated with the given email. + pub password: String, +} + +/// Sends a magic link to the given email address so an existing user can sign in +/// without a password. The user clicks the link in their email and is redirected to +/// `redirect_uri` with a token; pass that token to `/auth/verify_link` to obtain +/// session tokens. +/// +/// If no account exists for the email, the endpoint still returns success to prevent +/// email enumeration — no link is sent in that case. Both `email` and `redirect_uri` +/// are required. Requests are rate-limited per IP (10 per minute) and per email-IP pair +/// (3 per minute) — exceeding either limit returns HTTP 429. Returns HTTP 204 on success. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AuthLoginLinkInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address of the account to send the magic link to. + pub email: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL the user is redirected to after clicking the magic link. The token is appended as a query parameter. + pub redirect_uri: Option, +} + +/// Exchanges a valid refresh token for a new access token and a new refresh token, +/// rotating the refresh token on every call. The response also includes the updated +/// user object. Store the new refresh token and discard the old one. +/// +/// Refresh tokens are single-use — submitting an already-consumed token returns HTTP 401. +/// Rate limiting is applied per (user, IP) pair when the token can be verified, and +/// falls back to IP-only when it cannot. The limit is 30 exchanges per minute per +/// bucket; exceeding it returns HTTP 429. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AuthRefreshInput { + /// Refresh token previously issued by a login, registration, or token-refresh response. + pub refresh_token: String, +} + +/// Creates a new user account and returns an access token, refresh token, and the new +/// user object. Two registration paths are supported: +/// +/// - **Team registration**: supply `team_invite` with a valid team invite ID. The new +/// user is added to that team immediately upon registration. Returns HTTP 404 if the +/// invite is not found. +/// - **Standard registration**: supply `password`. An `invite_code` may optionally be +/// included for invite-gated apps; an invalid code returns HTTP 404. +/// +/// Exactly one of `team_invite` or `password` must be provided; omitting both returns +/// HTTP 400. Password registration must be enabled for the app; disabled apps return +/// HTTP 403. The response status is HTTP 201 on success. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AuthRegisterInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display alias (handle) for the new account. + pub alias: Option, + /// Email address for the new account. + pub email: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full name for the new account. + pub full_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Invite code for invite-gated registration. Applied only in the standard registration path. + pub invite_code: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Password for the new account. Required for standard (non-team-invite) registration. + pub password: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Create or reuse an organization from the work-email domain and stamp the new user into it. + pub set_org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team invite ID. When provided, the user is added to the team on registration. + pub team_invite: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// IANA timezone name for the new account, e.g. `"America/New_York"`. + pub timezone: Option, +} + +/// Starts a passwordless registration flow by sending a verification link to the given +/// email address. The recipient clicks the link and is redirected to `redirect_uri` with +/// a token; pass that token to `/auth/verify_link` to complete registration and obtain +/// session tokens. +/// +/// Profile fields (`full_name`, `alias`, `timezone`) are captured now and applied when +/// the link is verified. Requests are rate-limited per IP (10 per minute) and per +/// email-IP pair (3 per minute) — exceeding either limit returns HTTP 429. Returns +/// HTTP 204 on success. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AuthRegisterLinkInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display alias (handle) for the new account. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address to send the registration magic link to. + pub email: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full name for the new account. + pub full_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL the user is redirected to after clicking the registration link. The token is appended as a query parameter. + pub redirect_uri: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Create or reuse an organization from the work-email domain during confirmation. + pub set_org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// IANA timezone name for the new account, e.g. `"America/New_York"`. + pub timezone: Option, +} + +/// Sends a passwordless magic link to the given email address. If an account with that +/// email already exists, a login link is sent. If no account exists, a registration link +/// is sent and the recipient completes sign-up by clicking through. This unified endpoint +/// lets you implement a single email-entry UI that handles both cases transparently. +/// +/// The `redirect_uri` is validated against the app's registered hosts; an unregistered +/// URI returns HTTP 400. Both `email` and `redirect_uri` are required. Requests are +/// rate-limited per IP (10 per minute) and per email-IP pair (3 per minute). Returns +/// HTTP 204 on success — no body. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AuthRequestLinkInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address to send the magic link to. + pub email: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL the user is redirected to after clicking the magic link. Must be registered with the app. + pub redirect_uri: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// For a new user, create or reuse an organization from the work-email domain during confirmation. + pub set_org: Option, +} + +/// Consumes a single-use login token delivered via email and returns an access token, +/// refresh token, and the authenticated user object. One-time tokens are issued by the +/// passwordless login flow and expire after a short window; submitting an expired or +/// already-used token returns HTTP 401. +/// +/// If `timezone` is provided and the user's current timezone is still the default +/// (`"America/Los_Angeles"`), the account timezone is updated in the same request. +/// Requests are rate-limited to 10 per IP per minute; exceeding this returns HTTP 429. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AuthTokenInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// IANA timezone name to apply to the account if the account timezone is still the default, e.g. `"Europe/London"`. Omit to leave the timezone unchanged. + pub timezone: Option, + /// Single-use login token extracted from the magic link or email code flow. + pub token: String, +} + +/// Consumes a single-use token from a magic link URL and returns an access token, +/// refresh token, and the authenticated user object. This endpoint completes both the +/// login flow (initiated by `/auth/request_login_link`) and the registration flow +/// (initiated by `/auth/request_register_link` or `/auth/request_link`). +/// +/// Extract the token from the `token` query parameter of the magic link redirect URI +/// and POST it here. Expired or already-used tokens return HTTP 401 — expired links +/// carry the error code `expired_token`, unknown or already-used tokens carry +/// `invalid_or_expired_token`. If the app has disabled passwordless authentication +/// the request returns HTTP 403. Rate-limited to 10 requests per IP per minute — +/// exceeding this returns HTTP 429. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AuthVerifyLinkInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Single-use magic link token extracted from the redirect URI query parameter. + pub token: Option, +} + +/// Authentication API resource. +#[derive(Clone)] +pub struct Auth { + pub(crate) client: Client, +} + +impl Auth { + /// List supported auth methods + pub async fn get_api_v1_auth_allowed_auth_methods( + &self, + ) -> Result { + let path = "/api/v1/auth/allowed_auth_methods".to_owned(); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get_api_v1_auth_allowed_auth_methods]. + #[cfg(feature = "blocking")] + pub fn get_api_v1_auth_allowed_auth_methods_blocking( + &self, + ) -> Result { + crate::blocking::block_on(self.get_api_v1_auth_allowed_auth_methods()) + } + /// Authenticate with email and password + pub async fn post_api_v1_auth_login( + &self, + body: &PostApiV1AuthLoginInput, + ) -> Result { + let path = "/api/v1/auth/login".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::post_api_v1_auth_login]. + #[cfg(feature = "blocking")] + pub fn post_api_v1_auth_login_blocking( + &self, + body: &PostApiV1AuthLoginInput, + ) -> Result { + crate::blocking::block_on(self.post_api_v1_auth_login(body)) + } + /// Request a magic link for login + pub async fn request_login_magic_link(&self, body: &PostApiV1AuthLoginLinkInput) -> Result<()> { + let path = "/api/v1/auth/login/link".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send_empty().await + } + /// Blocking variant of [Self::request_login_magic_link]. + #[cfg(feature = "blocking")] + pub fn request_login_magic_link_blocking( + &self, + body: &PostApiV1AuthLoginLinkInput, + ) -> Result<()> { + crate::blocking::block_on(self.request_login_magic_link(body)) + } + /// Refresh an access token + pub async fn post_api_v1_auth_refresh( + &self, + body: &PostApiV1AuthRefreshInput, + ) -> Result { + let path = "/api/v1/auth/refresh".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::post_api_v1_auth_refresh]. + #[cfg(feature = "blocking")] + pub fn post_api_v1_auth_refresh_blocking( + &self, + body: &PostApiV1AuthRefreshInput, + ) -> Result { + crate::blocking::block_on(self.post_api_v1_auth_refresh(body)) + } + /// Register a new user with email and password + pub async fn post_api_v1_auth_register( + &self, + body: &PostApiV1AuthRegisterInput, + ) -> Result { + let path = "/api/v1/auth/register".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::post_api_v1_auth_register]. + #[cfg(feature = "blocking")] + pub fn post_api_v1_auth_register_blocking( + &self, + body: &PostApiV1AuthRegisterInput, + ) -> Result { + crate::blocking::block_on(self.post_api_v1_auth_register(body)) + } + /// Request a magic link for registration + pub async fn request_register_magic_link( + &self, + body: &PostApiV1AuthRegisterLinkInput, + ) -> Result<()> { + let path = "/api/v1/auth/register/link".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send_empty().await + } + /// Blocking variant of [Self::request_register_magic_link]. + #[cfg(feature = "blocking")] + pub fn request_register_magic_link_blocking( + &self, + body: &PostApiV1AuthRegisterLinkInput, + ) -> Result<()> { + crate::blocking::block_on(self.request_register_magic_link(body)) + } + /// Request a magic link for login or registration + pub async fn request_magic_link(&self, body: &PostApiV1AuthRequestLinkInput) -> Result<()> { + let path = "/api/v1/auth/request/link".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send_empty().await + } + /// Blocking variant of [Self::request_magic_link]. + #[cfg(feature = "blocking")] + pub fn request_magic_link_blocking(&self, body: &PostApiV1AuthRequestLinkInput) -> Result<()> { + crate::blocking::block_on(self.request_magic_link(body)) + } + /// Exchange a one-time login token for session tokens + pub async fn exchange_login_token(&self, body: &PostApiV1AuthTokenInput) -> Result { + let path = "/api/v1/auth/token".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::exchange_login_token]. + #[cfg(feature = "blocking")] + pub fn exchange_login_token_blocking( + &self, + body: &PostApiV1AuthTokenInput, + ) -> Result { + crate::blocking::block_on(self.exchange_login_token(body)) + } + /// Verify a magic link token + pub async fn verify_magic_link( + &self, + body: &PostApiV1AuthVerifyLinkInput, + ) -> Result { + let path = "/api/v1/auth/verify/link".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::verify_magic_link]. + #[cfg(feature = "blocking")] + pub fn verify_magic_link_blocking( + &self, + body: &PostApiV1AuthVerifyLinkInput, + ) -> Result { + crate::blocking::block_on(self.verify_magic_link(body)) + } +} + +impl Client { + /// Authenticate with email/password and enable generation-fenced automatic refresh. + pub async fn with_credentials( + api_key: impl Into, + email: impl Into, + password: impl Into, + ) -> Result { + let client = Self::builder().publishable_key(api_key).build()?; + let tokens = client + .auth() + .post_api_v1_auth_login(&PostApiV1AuthLoginInput { + email: email.into(), + password: password.into(), + }) + .await?; + client + .install_session( + tokens.token.clone(), + Some(tokens.refresh_token.clone()), + "/api/v1/auth/refresh", + ) + .await; + Ok(client) + } +} diff --git a/src/generated/channels.rs b/src/generated/channels.rs new file mode 100644 index 0000000..a5ef02a --- /dev/null +++ b/src/generated/channels.rs @@ -0,0 +1,1864 @@ +// Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License. +// This file is auto-generated by @archastro/sdk-generator. Do not edit. +// Content hash: c35ce7867ef7 + +use crate::{Channel, ChannelEventStream, Result, Socket}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +/// List activity feed entries with cursor-based pagination +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiActivityFeedChannelListEntriesInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub kind: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub level: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub limit: Option, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiActivityFeedChannelNewEntryPayload { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub entry: Option>, +} +/// Phoenix channel for real-time activity feed updates. +/// +/// Clients join a topic scoped to an agent or org and receive +/// `new_entry` events as feed entries are created. +/// +/// ## Topics +/// +/// * `"api:activity_feed:agent:{agent_user_id}"` — entries for a specific agent +/// * `"api:activity_feed:org:{org_id}"` — entries for an entire org/tenant +/// +#[derive(Clone)] +pub struct ApiActivityFeedChannel { + /// Underlying joined Phoenix channel. + pub channel: Channel, + /// Typed payload returned by the join. + pub join_response: R, +} +impl ApiActivityFeedChannel { + /// Join an agent-scoped activity feed + pub async fn join_agent( + socket: &Socket, + agent_id: &str, + ) -> Result>> { + let topic = "api:activity_feed:agent:{agent_id}".replace("{agent_id}", agent_id); + let channel = socket.channel(topic); + let value = channel.join(serde_json::json!({})).await?; + let join_response = serde_json::from_value(value)?; + Ok(ApiActivityFeedChannel { + channel, + join_response, + }) + } + /// Join an org-scoped activity feed + pub async fn join_org( + socket: &Socket, + org_id: &str, + ) -> Result>> { + let topic = "api:activity_feed:org:{org_id}".replace("{org_id}", org_id); + let channel = socket.channel(topic); + let value = channel.join(serde_json::json!({})).await?; + let join_response = serde_json::from_value(value)?; + Ok(ApiActivityFeedChannel { + channel, + join_response, + }) + } +} +impl ApiActivityFeedChannel { + /// Leave the underlying Phoenix channel. + pub async fn leave(&self) -> Result<()> { + self.channel.leave().await + } + /// List activity feed entries with cursor-based pagination + pub async fn list_entries( + &self, + input: &ApiActivityFeedChannelListEntriesInput, + ) -> Result { + let value = self + .channel + .push("list_entries", serde_json::to_value(input)?) + .await?; + Ok(serde_json::from_value(value)?) + } + /// Subscribe to new_entry pushes. + pub fn subscribe_new_entry(&self) -> ChannelEventStream { + self.channel.subscribe("new_entry") + } +} + +/// Fork a sub-thread from an existing message +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelApiChatForkThreadInput { + /// API field. + pub message_id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub title: Option, +} +/// Mark a thread as read up to a given message +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelApiChatMarkThreadReadInput { + /// API field. + pub message_id: String, +} +/// Load additional messages with cursor-based pagination +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelApiChatLoadMoreMessagesInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub include_metadata: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub limit: Option, +} +/// Post a new message with optional uploads and reply-to +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelApiChatPostMessageInput { + /// API field. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub idempotency_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub reply_to: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub uploads: Option>>, +} +/// Post a simple text message +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelApiChatPostSimpleMessageInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub idempotency_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub reply_to: Option, +} +/// Edit an existing message's content +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelApiChatEditMessageInput { + /// API field. + pub content: String, + /// API field. + pub message_id: String, +} +/// Delete a message +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelApiChatDeleteMessageInput { + /// API field. + pub message_id: String, +} +/// Add an emoji reaction to a message +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelApiChatAddReactionInput { + /// API field. + pub emoji: String, + /// API field. + pub message_id: String, +} +/// Remove an emoji reaction from a message +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelApiChatRemoveReactionInput { + /// API field. + pub emoji: String, + /// API field. + pub message_id: String, +} +/// Signal that the current user has started or stopped typing in the thread +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelApiChatTypingInput { + /// API field. + pub is_typing: bool, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageAddedPayloadMessageAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageAddedPayloadMessageAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageAddedPayloadMessageAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageAddedPayloadMessageAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageAddedPayloadMessageActorsItemProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageAddedPayloadMessageActorsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageAddedPayloadMessageAttachmentsItemImageSource { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageAddedPayloadMessageAttachmentsItemVariantsItemImageSource { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageAddedPayloadMessageAttachmentsItemVariantsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of this variant's file (e.g., `"image/jpeg"`, `"video/mp4"`). `null` if the file is not loaded. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this variant was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file that backs this variant (`fil_...`). + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the uploaded file for this variant. `null` if the file is not loaded. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of this variant in pixels. `null` if not recorded. + pub height: Option, + /// Media variant ID (`mvr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types. + pub image_source: + Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this variant was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed download URL for this variant, resolved at request time. `null` if the file is unavailable. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier for this variant's processing tier. Common values include `"original"` (the unmodified upload) and `"thumbnail"` (a resized preview). + pub variant_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of this variant in pixels. `null` if not recorded. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageAddedPayloadMessageAttachmentsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the attached file, e.g. `"image/png"` or `"application/pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the attached file, e.g. `"report.pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height in pixels of the media item. Present on `media` type only. `null` otherwise. + pub height: Option, + /// Unique identifier for this attachment within the message. + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise. + pub image_height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise. + pub image_source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise. + pub image_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise. + pub image_width: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The media category, e.g. `"video"` or `"audio"`. Present on `media` type only. `null` otherwise. + pub media_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the media item. Present on `media` type only. `null` otherwise. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types. + pub object: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types. + pub title: Option, + #[serde(rename = "type")] + /// The attachment type. One of `"file"`, `"scraped_link"`, `"artifact"`, `"task"`, `"media"`, `"action"`, or `"chart"`. Determines which additional fields are present. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise. + pub variants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise. + pub version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width in pixels of the media item. Present on `media` type only. `null` otherwise. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageAddedPayloadMessageReactionsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Type-specific reaction data. For `"emoji_reaction"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `"👍"`). + pub payload: Option>, + #[serde(rename = "type")] + /// Reaction type identifier. Currently always `"emoji_reaction"` for emoji-based reactions. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Public ID of the user who added the reaction (`usr_...`). + pub user: Option, +} + +/// Contract-defined values for ApiChatChannelMessageAddedPayloadMessageAgentMode. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ApiChatChannelMessageAddedPayloadMessageAgentMode { + /// The cli wire value. + #[serde(rename = "cli")] + Cli, + /// The embedded wire value. + #[serde(rename = "embedded")] + Embedded, +} + +/// Contract-defined values for ApiChatChannelMessageAddedPayloadMessageVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ApiChatChannelMessageAddedPayloadMessageVisibility { + /// The default wire value. + #[serde(rename = "default")] + Default, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageAddedPayloadMessage { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry. + pub actors: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path. + pub agent_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments. + pub attachments: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread. + pub branched_thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Text content of the message. `null` for messages that contain only attachments. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the message was posted (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this message has at least one reply. Only present when explicitly requested or computed by the server. + pub has_replies: Option, + /// Message ID (`msg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one. + pub idempotency_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages. + pub is_deleted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users. + pub legacy_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization that owns this message (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded. + pub reactions: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display hint for how the message should be rendered. One of `"reply"`, `"direct"`, or `"inline"`. `null` for user-authored messages, which are always rendered as standard replies. + pub rendering_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message. + pub replies: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response. + pub replies_after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response. + pub replies_before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of direct replies to this message. Only present when explicitly requested or computed by the server. + pub reply_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded. + pub reply_to: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages. + pub root_message_id: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread. + pub thread: Option, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees. + pub visibility: Option, +} + +/// Broadcast when a new message is added to a thread +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageAddedPayload { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata. + pub message: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub thread_id: Option, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageUpdatedPayloadMessageAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageUpdatedPayloadMessageAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageUpdatedPayloadMessageAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageUpdatedPayloadMessageAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageUpdatedPayloadMessageActorsItemProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageUpdatedPayloadMessageActorsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageUpdatedPayloadMessageAttachmentsItemImageSource { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageUpdatedPayloadMessageAttachmentsItemVariantsItemImageSource { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageUpdatedPayloadMessageAttachmentsItemVariantsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of this variant's file (e.g., `"image/jpeg"`, `"video/mp4"`). `null` if the file is not loaded. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this variant was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file that backs this variant (`fil_...`). + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the uploaded file for this variant. `null` if the file is not loaded. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of this variant in pixels. `null` if not recorded. + pub height: Option, + /// Media variant ID (`mvr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types. + pub image_source: + Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this variant was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed download URL for this variant, resolved at request time. `null` if the file is unavailable. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier for this variant's processing tier. Common values include `"original"` (the unmodified upload) and `"thumbnail"` (a resized preview). + pub variant_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of this variant in pixels. `null` if not recorded. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageUpdatedPayloadMessageAttachmentsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the attached file, e.g. `"image/png"` or `"application/pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the attached file, e.g. `"report.pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height in pixels of the media item. Present on `media` type only. `null` otherwise. + pub height: Option, + /// Unique identifier for this attachment within the message. + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise. + pub image_height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise. + pub image_source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise. + pub image_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise. + pub image_width: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The media category, e.g. `"video"` or `"audio"`. Present on `media` type only. `null` otherwise. + pub media_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the media item. Present on `media` type only. `null` otherwise. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types. + pub object: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types. + pub title: Option, + #[serde(rename = "type")] + /// The attachment type. One of `"file"`, `"scraped_link"`, `"artifact"`, `"task"`, `"media"`, `"action"`, or `"chart"`. Determines which additional fields are present. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise. + pub variants: + Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise. + pub version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width in pixels of the media item. Present on `media` type only. `null` otherwise. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageUpdatedPayloadMessageReactionsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Type-specific reaction data. For `"emoji_reaction"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `"👍"`). + pub payload: Option>, + #[serde(rename = "type")] + /// Reaction type identifier. Currently always `"emoji_reaction"` for emoji-based reactions. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Public ID of the user who added the reaction (`usr_...`). + pub user: Option, +} + +/// Contract-defined values for ApiChatChannelMessageUpdatedPayloadMessageAgentMode. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ApiChatChannelMessageUpdatedPayloadMessageAgentMode { + /// The cli wire value. + #[serde(rename = "cli")] + Cli, + /// The embedded wire value. + #[serde(rename = "embedded")] + Embedded, +} + +/// Contract-defined values for ApiChatChannelMessageUpdatedPayloadMessageVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ApiChatChannelMessageUpdatedPayloadMessageVisibility { + /// The default wire value. + #[serde(rename = "default")] + Default, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageUpdatedPayloadMessage { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry. + pub actors: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path. + pub agent_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments. + pub attachments: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread. + pub branched_thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Text content of the message. `null` for messages that contain only attachments. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the message was posted (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this message has at least one reply. Only present when explicitly requested or computed by the server. + pub has_replies: Option, + /// Message ID (`msg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one. + pub idempotency_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages. + pub is_deleted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users. + pub legacy_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization that owns this message (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded. + pub reactions: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display hint for how the message should be rendered. One of `"reply"`, `"direct"`, or `"inline"`. `null` for user-authored messages, which are always rendered as standard replies. + pub rendering_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message. + pub replies: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response. + pub replies_after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response. + pub replies_before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of direct replies to this message. Only present when explicitly requested or computed by the server. + pub reply_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded. + pub reply_to: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages. + pub root_message_id: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread. + pub thread: Option, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees. + pub visibility: Option, +} + +/// Broadcast when a message is updated or removed +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelMessageUpdatedPayload { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata. + pub message: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub thread_id: Option, +} +/// Broadcast thread-level events (agent updates, read state, unread counts) +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelThreadEventPayload { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub payload: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub thread_id: Option, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub type_: Option, +} +/// Broadcast system-wide events +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelSystemEventPayload { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub event: Option>, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelTypingPayloadActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelTypingPayloadActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option, +} + +/// Broadcast when a participant (human or agent) starts or stops typing. Ephemeral; never persisted. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelTypingPayload { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The entity that authored a message, either a human user or an agent. + pub actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub is_typing: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub thread_id: Option, +} +/// Join a team-scoped thread by ID +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelJoinTeamThreadParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub include_metadata: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub limit: Option, +} +/// Join or create a team-scoped keyed thread +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelJoinTeamKeyedParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub include_metadata: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub limit: Option, +} +/// Join a team-scoped transient (ephemeral) thread +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelJoinTeamTransientParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub include_metadata: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub limit: Option, +} +/// Join a user-scoped thread by ID +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelJoinUserThreadParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub include_metadata: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub limit: Option, +} +/// Join or create a user-scoped keyed thread +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelJoinUserKeyedParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub include_metadata: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub limit: Option, +} +/// Join a user-scoped transient (ephemeral) thread +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiChatChannelJoinUserTransientParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub include_metadata: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub limit: Option, +} +/// Channel for real-time chat messaging. +/// +/// Supports team-scoped and user-scoped threads with keyed, transient, and direct +/// thread access patterns. +/// +#[derive(Clone)] +pub struct ApiChatChannel { + /// Underlying joined Phoenix channel. + pub channel: Channel, + /// Typed payload returned by the join. + pub join_response: R, +} +impl ApiChatChannel { + /// Join a team-scoped thread by ID + pub async fn join_team_thread( + socket: &Socket, + team_id: &str, + thread_id: &str, + params: &ApiChatChannelJoinTeamThreadParams, + ) -> Result>> { + let topic = "api:chat:team:{team_id}:thread:{thread_id}" + .replace("{team_id}", team_id) + .replace("{thread_id}", thread_id); + let channel = socket.channel(topic); + let value = channel.join(serde_json::to_value(params)?).await?; + let join_response = serde_json::from_value(value)?; + Ok(ApiChatChannel { + channel, + join_response, + }) + } + /// Join or create a team-scoped keyed thread + pub async fn join_team_keyed( + socket: &Socket, + team_id: &str, + key: &str, + params: &ApiChatChannelJoinTeamKeyedParams, + ) -> Result>> { + let topic = "api:chat:team:{team_id}:key:{key}" + .replace("{team_id}", team_id) + .replace("{key}", key); + let channel = socket.channel(topic); + let value = channel.join(serde_json::to_value(params)?).await?; + let join_response = serde_json::from_value(value)?; + Ok(ApiChatChannel { + channel, + join_response, + }) + } + /// Join a team-scoped transient (ephemeral) thread + pub async fn join_team_transient( + socket: &Socket, + team_id: &str, + key: &str, + params: &ApiChatChannelJoinTeamTransientParams, + ) -> Result>> { + let topic = "api:chat:team:{team_id}:transient:{key}" + .replace("{team_id}", team_id) + .replace("{key}", key); + let channel = socket.channel(topic); + let value = channel.join(serde_json::to_value(params)?).await?; + let join_response = serde_json::from_value(value)?; + Ok(ApiChatChannel { + channel, + join_response, + }) + } + /// Join a user-scoped thread by ID + pub async fn join_user_thread( + socket: &Socket, + thread_id: &str, + params: &ApiChatChannelJoinUserThreadParams, + ) -> Result>> { + let topic = "api:chat:user:thread:{thread_id}".replace("{thread_id}", thread_id); + let channel = socket.channel(topic); + let value = channel.join(serde_json::to_value(params)?).await?; + let join_response = serde_json::from_value(value)?; + Ok(ApiChatChannel { + channel, + join_response, + }) + } + /// Join or create a user-scoped keyed thread + pub async fn join_user_keyed( + socket: &Socket, + key: &str, + params: &ApiChatChannelJoinUserKeyedParams, + ) -> Result>> { + let topic = "api:chat:user:key:{key}".replace("{key}", key); + let channel = socket.channel(topic); + let value = channel.join(serde_json::to_value(params)?).await?; + let join_response = serde_json::from_value(value)?; + Ok(ApiChatChannel { + channel, + join_response, + }) + } + /// Join a user-scoped transient (ephemeral) thread + pub async fn join_user_transient( + socket: &Socket, + key: &str, + params: &ApiChatChannelJoinUserTransientParams, + ) -> Result>> { + let topic = "api:chat:user:transient:{key}".replace("{key}", key); + let channel = socket.channel(topic); + let value = channel.join(serde_json::to_value(params)?).await?; + let join_response = serde_json::from_value(value)?; + Ok(ApiChatChannel { + channel, + join_response, + }) + } +} +impl ApiChatChannel { + /// Leave the underlying Phoenix channel. + pub async fn leave(&self) -> Result<()> { + self.channel.leave().await + } + /// Fork a sub-thread from an existing message + pub async fn api_chat_fork_thread( + &self, + input: &ApiChatChannelApiChatForkThreadInput, + ) -> Result { + let value = self + .channel + .push("api:chat:fork_thread", serde_json::to_value(input)?) + .await?; + Ok(serde_json::from_value(value)?) + } + /// Mark a thread as read up to a given message + pub async fn api_chat_mark_thread_read( + &self, + input: &ApiChatChannelApiChatMarkThreadReadInput, + ) -> Result { + let value = self + .channel + .push("api:chat:mark_thread_read", serde_json::to_value(input)?) + .await?; + Ok(serde_json::from_value(value)?) + } + /// List all messages in the current thread + pub async fn api_chat_list_messages(&self) -> Result { + let value = self + .channel + .push("api:chat:list_messages", serde_json::json!({})) + .await?; + Ok(serde_json::from_value(value)?) + } + /// Load additional messages with cursor-based pagination + pub async fn api_chat_load_more_messages( + &self, + input: &ApiChatChannelApiChatLoadMoreMessagesInput, + ) -> Result { + let value = self + .channel + .push("api:chat:load_more_messages", serde_json::to_value(input)?) + .await?; + Ok(serde_json::from_value(value)?) + } + /// Post a new message with optional uploads and reply-to + pub async fn api_chat_post_message( + &self, + input: &ApiChatChannelApiChatPostMessageInput, + ) -> Result { + let value = self + .channel + .push("api:chat:post_message", serde_json::to_value(input)?) + .await?; + Ok(serde_json::from_value(value)?) + } + /// Post a simple text message + pub async fn api_chat_post_simple_message( + &self, + input: &ApiChatChannelApiChatPostSimpleMessageInput, + ) -> Result { + let value = self + .channel + .push("api:chat:post_simple_message", serde_json::to_value(input)?) + .await?; + Ok(serde_json::from_value(value)?) + } + /// Edit an existing message's content + pub async fn api_chat_edit_message( + &self, + input: &ApiChatChannelApiChatEditMessageInput, + ) -> Result { + let value = self + .channel + .push("api:chat:edit_message", serde_json::to_value(input)?) + .await?; + Ok(serde_json::from_value(value)?) + } + /// Delete a message + pub async fn api_chat_delete_message( + &self, + input: &ApiChatChannelApiChatDeleteMessageInput, + ) -> Result { + let value = self + .channel + .push("api:chat:delete_message", serde_json::to_value(input)?) + .await?; + Ok(serde_json::from_value(value)?) + } + /// Add an emoji reaction to a message + pub async fn api_chat_add_reaction( + &self, + input: &ApiChatChannelApiChatAddReactionInput, + ) -> Result { + let value = self + .channel + .push("api:chat:add_reaction", serde_json::to_value(input)?) + .await?; + Ok(serde_json::from_value(value)?) + } + /// Remove an emoji reaction from a message + pub async fn api_chat_remove_reaction( + &self, + input: &ApiChatChannelApiChatRemoveReactionInput, + ) -> Result { + let value = self + .channel + .push("api:chat:remove_reaction", serde_json::to_value(input)?) + .await?; + Ok(serde_json::from_value(value)?) + } + /// Signal that the current user has started or stopped typing in the thread + pub async fn api_chat_typing(&self, input: &ApiChatChannelApiChatTypingInput) -> Result { + let value = self + .channel + .push("api:chat:typing", serde_json::to_value(input)?) + .await?; + Ok(serde_json::from_value(value)?) + } + /// Broadcast when a new message is added to a thread + pub fn subscribe_message_added(&self) -> ChannelEventStream { + self.channel.subscribe("message_added") + } + /// Broadcast when a message is updated or removed + pub fn subscribe_message_updated( + &self, + ) -> ChannelEventStream { + self.channel.subscribe("message_updated") + } + /// Broadcast thread-level events (agent updates, read state, unread counts) + pub fn subscribe_thread_event(&self) -> ChannelEventStream { + self.channel.subscribe("thread_event") + } + /// Broadcast system-wide events + pub fn subscribe_system_event(&self) -> ChannelEventStream { + self.channel.subscribe("system_event") + } + /// Broadcast when a participant (human or agent) starts or stops typing. Ephemeral; never persisted. + pub fn subscribe_typing(&self) -> ChannelEventStream { + self.channel.subscribe("typing") + } +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiObjectChannelUpdateFieldsInput { + /// API field. + pub fields: std::collections::BTreeMap, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub operation_id: Option, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiObjectChannelPresenceUpdateInput { + /// API field. + pub presence: std::collections::BTreeMap, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiObjectChannelObjectUpdatedPayload { + /// API field. + pub fields: std::collections::BTreeMap, + /// API field. + pub id: String, + /// API field. + pub operation_id: String, + /// API field. + pub partial: bool, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiObjectChannelObjectCreatedPayload { + /// API field. + pub connection_id: String, + /// API field. + pub fields: std::collections::BTreeMap, + /// API field. + pub id: String, + /// API field. + pub presence: Vec>, + /// API field. + pub readonly: bool, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiObjectChannelObjectDeletedPayload { + /// API field. + pub id: String, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiObjectChannelPresenceUpdatedPayload { + /// API field. + pub presence: std::collections::BTreeMap, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiObjectChannelPresenceLeftPayload { + /// API field. + pub connection_id: String, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiObjectChannelAccessRevokedPayload { + /// API field. + pub reason: String, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiObjectChannelJoinByIdParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub connection_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub partial_updates: Option, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiObjectChannelJoinByIdResponse { + /// Collision-free identifier for this browser connection. + pub connection_id: String, + /// Current materialized fields, or `null` while waiting for object creation. + pub fields: Option>, + /// Custom-object ID, or `null` while a row-key subscription waits for creation. + pub id: Option, + /// Current ephemeral collaborator presence. + pub presence: Vec>, + /// Whether the current connection may only read the object. + pub readonly: bool, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiObjectChannelJoinByRowKeyParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub connection_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub partial_updates: Option, +} +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiObjectChannelJoinByRowKeyResponse { + /// Collision-free identifier for this browser connection. + pub connection_id: String, + /// Current materialized fields, or `null` while waiting for object creation. + pub fields: Option>, + /// Custom-object ID, or `null` while a row-key subscription waits for creation. + pub id: Option, + /// Current ephemeral collaborator presence. + pub presence: Vec>, + /// Whether the current connection may only read the object. + pub readonly: bool, +} +/// Channel for real-time custom object collaboration. +/// +/// Clients join `api:object:{object_id}` to receive the current object state +/// and subscribe to field-level updates. Mutations are sent as key:value maps. +/// +#[derive(Clone)] +pub struct ApiObjectChannel { + /// Underlying joined Phoenix channel. + pub channel: Channel, + /// Typed payload returned by the join. + pub join_response: R, +} +impl ApiObjectChannel { + /// Join api:object:{object_id}. + pub async fn join_by_id( + socket: &Socket, + object_id: &str, + params: &ApiObjectChannelJoinByIdParams, + ) -> Result> { + let topic = "api:object:{object_id}".replace("{object_id}", object_id); + let channel = socket.channel(topic); + let value = channel.join(serde_json::to_value(params)?).await?; + let join_response = serde_json::from_value(value)?; + Ok(ApiObjectChannel { + channel, + join_response, + }) + } + /// Join api:object:{schema_type}:{row_key}. + pub async fn join_by_row_key( + socket: &Socket, + schema_type: &str, + row_key: &str, + params: &ApiObjectChannelJoinByRowKeyParams, + ) -> Result> { + let topic = "api:object:{schema_type}:{row_key}" + .replace("{schema_type}", schema_type) + .replace("{row_key}", row_key); + let channel = socket.channel(topic); + let value = channel.join(serde_json::to_value(params)?).await?; + let join_response = serde_json::from_value(value)?; + Ok(ApiObjectChannel { + channel, + join_response, + }) + } +} +impl ApiObjectChannel { + /// Leave the underlying Phoenix channel. + pub async fn leave(&self) -> Result<()> { + self.channel.leave().await + } + /// Push the update_fields event. + pub async fn update_fields(&self, input: &ApiObjectChannelUpdateFieldsInput) -> Result { + let value = self + .channel + .push("update_fields", serde_json::to_value(input)?) + .await?; + Ok(serde_json::from_value(value)?) + } + /// Push the save event. + pub async fn save(&self) -> Result { + let value = self.channel.push("save", serde_json::json!({})).await?; + Ok(serde_json::from_value(value)?) + } + /// Push the presence_update event. + pub async fn presence_update( + &self, + input: &ApiObjectChannelPresenceUpdateInput, + ) -> Result { + let value = self + .channel + .push("presence_update", serde_json::to_value(input)?) + .await?; + Ok(serde_json::from_value(value)?) + } + /// Subscribe to object_updated pushes. + pub fn subscribe_object_updated( + &self, + ) -> ChannelEventStream { + self.channel.subscribe("object_updated") + } + /// Subscribe to object_created pushes. + pub fn subscribe_object_created( + &self, + ) -> ChannelEventStream { + self.channel.subscribe("object_created") + } + /// Subscribe to object_deleted pushes. + pub fn subscribe_object_deleted( + &self, + ) -> ChannelEventStream { + self.channel.subscribe("object_deleted") + } + /// Subscribe to presence_updated pushes. + pub fn subscribe_presence_updated( + &self, + ) -> ChannelEventStream { + self.channel.subscribe("presence_updated") + } + /// Subscribe to presence_left pushes. + pub fn subscribe_presence_left( + &self, + ) -> ChannelEventStream { + self.channel.subscribe("presence_left") + } + /// Subscribe to access_revoked pushes. + pub fn subscribe_access_revoked( + &self, + ) -> ChannelEventStream { + self.channel.subscribe("access_revoked") + } +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiTasksChannelTasksUpdatedPayloadTasksItemCreatedByActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiTasksChannelTasksUpdatedPayloadTasksItemCreatedByActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiTasksChannelTasksUpdatedPayloadTasksItemCurrentLease { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the coding session. + pub harness: String, + /// Display name supplied by the coding session that holds the lease. + pub session_name: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiTasksChannelTasksUpdatedPayloadTasksItemOwnerActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiTasksChannelTasksUpdatedPayloadTasksItemOwnerActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiTasksChannelTasksUpdatedPayloadTasksItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind. + pub blocked_by_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open. + pub closed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of comments posted on this task. + pub comments_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted). + pub created_by_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted. + pub created_by_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted. + pub created_by_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included. + pub current_lease: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Long-form description or notes for the task. `null` if no description has been provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). `null` if no due date is set. + pub due_date: Option>, + /// Task ID (`tsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read. + pub is_blocked: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set. + pub metadata: Option>, + /// Human-readable title of the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted). + pub owner_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment. + pub sandbox: Option, + /// Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks. + pub subtasks_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team. + pub user: Option, +} + +/// Broadcast when the thread's task records change; carries a full snapshot +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ApiTasksChannelTasksUpdatedPayload { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub tasks: Option>, +} +/// Phoenix channel for live task-record updates. +/// +/// Clients join `api:tasks:thread:{thread_id}` to receive the thread's current +/// event-sourced tasks and subscribe to changes. The join reply carries a full +/// snapshot (`%{tasks: [...]}`), and every subsequent change lands as a +/// `tasks_updated` push carrying a fresh snapshot — the same replace-wholesale +/// contract expected by task-panel clients, so clients need no +/// delta bookkeeping. +/// +/// Change signals originate from `ArchAstro.Tasks.Projectors.TaskProjector`, +/// which broadcasts on `"tasks:thread:{thread_id}"` after each committed +/// projection. Bursts (e.g. a mirror reconcile dispatching several commands) +/// are coalesced: the first signal arms a short timer and the reload happens +/// once, after the burst settles. +/// +#[derive(Clone)] +pub struct ApiTasksChannel { + /// Underlying joined Phoenix channel. + pub channel: Channel, + /// Typed payload returned by the join. + pub join_response: R, +} +impl ApiTasksChannel { + /// Join a thread's live task list + pub async fn join_thread( + socket: &Socket, + thread_id: &str, + ) -> Result>> { + let topic = "api:tasks:thread:{thread_id}".replace("{thread_id}", thread_id); + let channel = socket.channel(topic); + let value = channel.join(serde_json::json!({})).await?; + let join_response = serde_json::from_value(value)?; + Ok(ApiTasksChannel { + channel, + join_response, + }) + } +} +impl ApiTasksChannel { + /// Leave the underlying Phoenix channel. + pub async fn leave(&self) -> Result<()> { + self.channel.leave().await + } + /// Broadcast when the thread's task records change; carries a full snapshot + pub fn subscribe_tasks_updated( + &self, + ) -> ChannelEventStream { + self.channel.subscribe("tasks_updated") + } +} diff --git a/src/generated/mod.rs b/src/generated/mod.rs new file mode 100644 index 0000000..ce4803e --- /dev/null +++ b/src/generated/mod.rs @@ -0,0 +1,17 @@ +// Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License. +// This file is auto-generated by @archastro/sdk-generator. Do not edit. +// Content hash: 90a51fed401d + +/// Generated authentication operations. +pub mod auth; +/// Generated Phoenix channel facades. +pub mod channels; +/// Generated API models. +pub mod types; +/// Generated v1 API resources. +pub mod v1; + +pub use auth::*; +pub use channels::*; +pub use types::*; +pub use v1::*; diff --git a/src/generated/types.rs b/src/generated/types.rs new file mode 100644 index 0000000..5096004 --- /dev/null +++ b/src/generated/types.rs @@ -0,0 +1,4637 @@ +// Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License. +// This file is auto-generated by @archastro/sdk-generator. Do not edit. +// Content hash: 291fb04517f7 + +#![allow(clippy::large_enum_variant)] +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +/// Terminal event marking the end of a streaming chat completion (SSE `done` event). +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AIChatStreamDone { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The overall finish reason for the completion. + pub finish_reason: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of model runs executed, including continuations triggered by tool calls. + pub run_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Aggregate token usage across every run in the completion (including tool-call continuations), keyed by model ID. + pub total_usage: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Token usage for the final run, keyed by model ID. + pub usage: Option>, +} + +/// Terminal error event for a streaming chat completion (SSE `error` event). +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AIChatStreamError { + /// Human-readable description of the error that terminated the stream. + pub message: String, +} + +/// A tool (function) call emitted by the assistant within an AI message. Mirrors the OpenAI tool-call object format. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AIToolCall { + /// Arguments the model wants to pass to the tool, as a key-value map. Deserialize and validate these against the tool's input schema before executing. + pub arguments: std::collections::BTreeMap, + /// Unique identifier for this tool call, assigned by the model. Use this value as `id` when submitting the corresponding tool result. + pub id: String, + /// Name of the tool or function the model wants to invoke, e.g. `"web_search"` or `"run_code"`. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque signature representing the model's internal reasoning that led to this tool call. `null` when the provider does not expose chain-of-thought data. + pub thought_signature: Option, +} + +/// The result of executing a tool call, submitted back to the model as a tool-role message. Mirrors the OpenAI tool-result object format. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AIToolResult { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Plain-text output produced by the tool execution. `null` when the result is expressed entirely through `resolution`. + pub content: Option, + /// ID of the tool call this result satisfies. Must match the `id` from the corresponding `AIToolCall`. + pub id: String, + /// Name of the tool or function that was executed, e.g. `"web_search"`. Must match the `name` from the corresponding `AIToolCall`. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Structured result data from the tool execution. Shape varies by tool. `null` when the result is expressed as plain text in `content`. + pub resolution: Option, +} + +/// A single message in an AI conversation, following the OpenAI-compatible chat format. Used in both request inputs and completion responses. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AIMessage { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Plain-text content of the message. Present for `system`, `user`, and `assistant` messages. `null` when the message body is expressed through `content_parts` or `tool_calls`. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Multimodal content parts for the message, used when the body includes images or mixed media. Each part is a map with a `type` key (`"text"`, `"image_url"`, or `"image_data"`). `null` when `content` is set. + pub content_parts: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque token that can be passed on a subsequent request to resume this conversation from the current state. `null` when the provider does not support conversation resumption. + pub resume_token: Option, + /// The speaker role for this message. One of `"system"`, `"user"`, `"assistant"`, or `"tool"`. + pub role: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Parsed structured data returned by the model when a JSON schema or structured-output mode was requested. Shape varies by the schema supplied at call time. `null` when structured output was not requested. + pub structured_output: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Tool calls requested by the model in an `assistant` message. Present only on assistant messages that invoke one or more tools. `null` on all other message roles. + pub tool_calls: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Tool execution results provided in a `tool` message. Each entry corresponds to a prior tool call by its `id`. `null` on all other message roles. + pub tool_results: Option>, +} + +/// The fully assembled assistant message for one run of a streaming chat completion (SSE `message_complete` event). +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AIChatStreamMessageComplete { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Why the model stopped generating this message, e.g. `"stop"`, `"length"`, or `"tool_calls"`. + pub finish_reason: Option, + /// The complete assistant message for this run, assembled from the preceding deltas. + pub message: AIMessage, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Token consumption for this run, keyed by model ID. `null` when usage data is unavailable. + pub usage: Option>, +} + +/// Incremental assistant text emitted during a streaming chat completion (SSE `message_delta` event). +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AIChatStreamMessageDelta { + /// The chunk of assistant text produced since the previous `message_delta` event. Concatenate deltas in order to reconstruct the message. + pub delta: String, +} + +/// Incremental model reasoning emitted during a streaming chat completion (SSE `thinking_delta` event). +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AIChatStreamThinkingDelta { + /// The chunk of model reasoning produced since the previous `thinking_delta` event. + pub delta: String, +} + +/// Incremental tool-call data emitted as the model assembles a tool invocation (SSE `tool_call_delta` event). +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AIChatStreamToolCallDelta { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// A chunk of the tool call's serialized arguments. Concatenate deltas to reconstruct the arguments JSON. + pub delta: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the tool call this delta belongs to, once the model has assigned one. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Name of the tool being called, once known. + pub name: Option, +} + +/// The result of a server-executed tool, streamed back into the run (SSE `tool_result` event). +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AIChatStreamToolResult { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The tool's output, serialized as a string. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the tool call this result satisfies. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Name of the tool that produced this result. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// How the tool call resolved, e.g. `"ok"` or `"error"`. + pub resolution: Option, +} + +/// The result of an AI chat completion request. Returned by chat completion endpoints after the model finishes generating. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AICompletionResult { + /// The reason the model stopped generating. Common values include `"stop"` (natural end), `"length"` (token limit reached), and `"tool_calls"` (the model invoked a tool). + pub finish_reason: String, + /// The final assistant message produced by the completion. + pub message: AIMessage, + /// The complete message history for the conversation, including all user, assistant, and tool messages in order. + pub messages: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Token consumption breakdown keyed by model ID. Each value is a map with `"input_tokens"` and `"output_tokens"` counts. `null` when usage data is unavailable. + pub token_usage: Option>, +} + +/// The result returned by an AI image generation or editing operation. Contains the generated image (as inline data or a URL) along with dimension, size, and usage metadata. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AIImageResult { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Aspect ratio of the generated image, e.g. `"16:9"` or `"1:1"`. `null` when not reported by the provider. + pub aspect_ratio: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the generated image in pixels. `null` when the provider does not report dimensions. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The generated image encoded as a base64 string. Present when the provider returns inline image data. `null` when `image_url` is set instead. + pub image_data: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolution tier label for the image, e.g. `"1K"` or `"2K"`. `null` when the provider does not include a tier label. + pub image_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the generated image, e.g. `"image/png"` or `"image/jpeg"`. `null` when the provider does not report a content type. + pub image_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Temporary URL pointing to the generated image hosted by the provider. Present when the provider returns a URL rather than inline data. `null` when `image_data` is set instead. + pub image_url: Option, + /// Identifier of the model that produced the image, e.g. `"dall-e-3"` or `"imagen-3"`. + pub model: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The prompt as rewritten by the provider before generation. Some providers (e.g. DALL-E 3) automatically expand or safety-check the original prompt. `null` when the provider does not revise prompts. + pub revised_prompt: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical size string as returned by the provider, e.g. `"1024x1024"`. `null` when not reported. + pub size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Provider-reported token and compute usage for the request. Structure varies by provider. `null` when usage data is unavailable. + pub usage: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the generated image in pixels. `null` when the provider does not report dimensions. + pub width: Option, +} + +/// A single access-control grant that pairs a principal with the set of actions it is allowed to perform. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AclGrant { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Identifies a principal to be removed from an access-control list. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AclRemoveTarget { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// An access-control list payload that supports either full replacement or targeted patch operations on a resource's grants. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Acl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Contract-defined alternatives for ActivityFeedEntryAgent. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ActivityFeedEntryAgent { + /// Variant1 union variant. + Variant1(String), + /// Variant2 union variant. + Variant2(Value), +} + +/// Contract-defined alternatives for ActivityFeedEntryUser. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ActivityFeedEntryUser { + /// Variant1 union variant. + Variant1(String), + /// Variant2 union variant. + Variant2(Value), +} + +/// A single event record in an activity feed, capturing what happened, who caused it, and which resources were involved. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ActivityFeedEntry { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The agent that produced this event. Returns an agent ID (`agi_...`) by default, or an expanded agent object when the association is loaded. `null` if no agent is associated. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the application that produced this entry (`dap_...`). `null` if not scoped to an app. + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of attachment objects associated with this entry. Each attachment has a `type` field (e.g. `"file"`, `"task"`, `"artifact"`) and type-specific additional fields. Empty array when there are no attachments. + pub attachments: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the automation run that produced this entry (`atr_...`). `null` if not produced by an automation run. + pub automation_run: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// A longer explanation of the event rendered as Markdown. `null` if no additional content is available. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// An opaque string used to group related entries together. Entries sharing the same `correlation_id` belong to a single logical operation. `null` if not correlated. + pub correlation_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this activity feed entry was created (ISO 8601). + pub created_at: Option>, + /// Activity feed entry ID (`afe_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The type of event this entry represents, e.g. `"agent_step"` or `"tool_call"`. Determines how `title`, `content`, and `attachments` should be interpreted. + pub kind: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Severity level of the event. One of `"info"`, `"warning"`, or `"error"`. `null` if no severity is set. + pub level: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata stored on this entry. Returns an empty object when no metadata is set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this entry belongs to (`org_...`). `null` if not org-scoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent routine run that produced this entry (`arr_...`). `null` if not produced by a routine run. + pub routine_run: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the sandbox environment this entry was generated in. `null` in production contexts. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent session record this entry belongs to (`ase_...`). `null` if not part of an agent session. + pub session_record: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team this entry is associated with (`tem_...`). `null` if not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this entry is associated with (`thr_...`). `null` if not linked to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// A one-line human-readable summary of the event. `null` if the entry has no title. + pub title: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this activity feed entry was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The user who triggered this event. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if no user is associated. + pub user: Option, +} + +/// A paginated list of activity feed entries returned by a feed query, with cursors for navigating backward and forward through results. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ActivityFeedEntryListResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass as `after` to retrieve the next page of entries. `null` when this is the last page. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass as `before` to retrieve the previous page of entries. `null` when this is the first page. + pub before_cursor: Option, + /// Array of activity feed entry objects for the current page, ordered by time descending. + pub entries: Vec, + /// Whether additional entries exist beyond the current page. When `true`, use `after_cursor` to fetch the next page. + pub has_more: bool, +} + +/// Resolved metadata for an image, including its delivery URL, dimensions, and optional references to the underlying storage file or media record. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ImageSource { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// The entity that authored a message, either a human user or an agent. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Actor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option, +} + +/// A named participant slot declared by an automation's workflow. Embedded stages hand work to the agent the invoker names for the slot. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AutomationParticipantSlot { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Workflow-authored explanation of the slot's role. `null` when the workflow declares none. + pub description: Option, + /// The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking. + pub name: String, + /// Whether the workflow requires this slot to be filled for the run to complete its embedded stages. + pub required: bool, + #[serde(rename = "type")] + /// The kind of principal the slot accepts. Currently always `"agent_user"` — the value supplied at invoke is an agent ID (`agi_...`). + pub type_: String, +} + +/// Locked payload and participant values supplied by the automation owner. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AutomationPrefills { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected. + pub payload: Option>, +} + +/// The schema-driven values an installer may lock when provisioning an invoked automation template. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionAutomationInvokeContract { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured. + pub input_schema: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs. + pub participants: Option>, + /// Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected. + pub prefills: AutomationPrefills, +} + +/// Contract-defined values for SolutionAutomationTemplateDetailsType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum SolutionAutomationTemplateDetailsType { + /// The automation wire value. + #[serde(rename = "automation")] + Automation, +} + +/// AutomationTemplate-specific details exposed by a Solution template summary. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionAutomationTemplateDetails { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Automation execution type (`invoked`, `scheduled`, or `trigger`). + pub automation_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning. + pub invoke_contract: Option, + #[serde(rename = "type")] + /// Template-details discriminator. Always `automation` for this variant. + pub type_: SolutionAutomationTemplateDetailsType, +} + +/// Template-kind-specific Solution summary details, discriminated by `type`. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum SolutionTemplateDetails { + /// SolutionAutomationTemplateDetails union variant. + SolutionAutomationTemplateDetails(SolutionAutomationTemplateDetails), +} + +/// Identity and display metadata for a single template bundled by a Solution, used to represent each wrapped or sibling template at template granularity. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionTemplateSummary { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details. + pub details: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`. + pub display_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template config ID (`cfg_...`). `null` for inline-only templates. + pub id: Option, + /// Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lookup key stamped on the template config at import time. `null` when no lookup key was assigned. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable virtual path assigned to the template config. `null` when no virtual path was set. + pub virtual_path: Option, +} + +/// A catalog entry for an imported Solution, including its display metadata, bundled templates, owner scopes, and any available upgrade information. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionSummary { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none. + pub category_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was first imported (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none. + pub events: Option>, + /// Solution config ID (`cfg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only. + pub image_url: Option, + /// Resource type. Always `"Solution"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise. + pub latest_solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise. + pub latest_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing display name declared in the Solution body. `null` when the Solution body does not set one. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo. + pub org_logo: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve. + pub org_slug: Option, + /// Owner scopes this Solution appears under. Members: `"system"` (app-level system scope) and/or `"org"` (viewer's org scope). + pub owners: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only. + pub screenshot_urls: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it. + pub solution_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Semver string declared in the Solution body (e.g. `"1.2.0"`). `null` when the body does not declare a version. + pub solution_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Freeform tag keys declared in the Solution body. An empty array when the body declares none. + pub tag_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Wrapped template kind — `"AgentTemplate"`, `"AutomationTemplate"`, `"AgentRoutineTemplate"`, `"AgentToolTemplate"`, `"AgentComputerTemplate"`, or `"SolutionTemplateRef"` for ref-mode bundles. + pub template_kind: Option, + /// Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references. + pub templates: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was last modified (ISO 8601). + pub updated_at: Option>, + /// `true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows. + pub upgrade_available: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset. + pub virtual_path: Option, +} + +/// Compact summary of an AgentTemplate config referenced by an agent upgrade or source-solution response. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct UpgradeTemplateSummary { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this template config was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Description of the template from the config body. `null` if the current version has no `description` field. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name from the config body. `null` if the current version has no `display_name` field. + pub display_name: Option, + /// Template config ID (`cfg_...`). + pub id: String, + /// Config kind identifier for this template (e.g. `"agent_tool_template"`). + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable lookup key assigned to this template config. `null` if no lookup key is set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template name as stored in the config body. `null` if the current version has no `name` field. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this template config was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Virtual filesystem path for this template config. `null` if not set. + pub virtual_path: Option, +} + +/// Summary of the Solution and AgentTemplate that an agent was last provisioned from. +/// Returned on single-agent responses; `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentSourceSolution { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now. + pub current_solution: Option, + /// Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution. + pub solution: SolutionSummary, + /// Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from. + pub template: UpgradeTemplateSummary, +} + +/// An AI agent that can be configured with tools, routines, and skills, and invoked to handle conversations or tasks. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Agent { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the application that owns this agent (`dap_...`). + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the agent was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `"claude-3-7-sonnet-latest"`). + pub default_model: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of what the agent does. `null` if not set. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address provisioned for this agent. `null` if email delivery is not configured. + pub email: Option, + /// Agent ID (`agi_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// System-level identity prompt that shapes the agent's persona and behavior. + pub identity: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents. + pub last_applied_template_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable, user-defined identifier for this agent within the application. Unique per app. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the agent. Not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name for the agent. `null` if not set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name). + pub originator: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Phone number provisioned for this agent. `null` if SMS is not configured. + pub phone_number: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints. + pub source_solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`). + pub template_upgrade_available: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the agent was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped. + pub user: Option, +} + +/// A cloud computer resource provisioned for an agent to use for browser and desktop automation tasks. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentComputer { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this computer (`agi_...`). `null` if the computer is not yet assigned to an agent. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the app this computer belongs to (`dap_...`). + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Provider-specific configuration key-value pairs for the computer. Structure depends on the underlying compute provider. + pub config: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the computer was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable error description when `status` is `"error"`. `null` otherwise. + pub error_message: Option, + /// Computer ID (`cmp_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the computer last reported activity or received a command. `null` if the computer has never been active. + pub last_active_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Unique, stable identifier you assign to this computer within its app. `null` if not set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata you attached to the computer. `null` if none was provided. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name for the computer. `null` if not set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Compute backend powering this computer: `"sprites"` (Fly Sprites) or `"vercel"` (Vercel Sandbox). + pub provider: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Cloud region where the computer is hosted, e.g. `"us-east-1"`. `null` if not yet assigned or when the provider has no region concept (e.g. `"vercel"`). + pub region: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL of the live screenshot sprite used to render a real-time preview of the computer's screen. `null` when no sprite is available. + pub sprite_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current lifecycle state of the computer. Common values include `"provisioning"`, `"ready"`, `"error"`, and `"terminated"`. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the computer record was last modified (ISO 8601). + pub updated_at: Option>, +} + +/// A list of agent computers returned by a list query. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentComputerListResponse { + /// Array of agent computer objects matching the query. + pub data: Vec, +} + +/// A slim summary of a single config record created during an agent install transaction. Returned as an entry in `AgentCreateResponse.installed_configs`. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct InstalledConfigEntry { + /// ID of the persisted config record (`cfg_...`). + pub id: String, + /// Caller-supplied correlation key echoed back from the request. For top-level configs this is the original `lookup_key` (before any suffix is applied). For skill file children it is the composite `":"` string, since file rows have no lookup_key of their own. + pub key: String, + /// Type of config that was created. One of `"Skill"`, `"File"`, `"Script"`, `"AgentTemplate"`, or `"Config"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stored `lookup_key` for this config after any suffix has been applied. `null` for `File` children inside a skill bundle, which are keyed by `(parent_id, relative_path)` rather than by `lookup_key`. + pub lookup_key: Option, +} + +/// The response returned by `POST /api/v1/agents`. Contains all agent fields plus an optional `installed_configs` array when a `template_bundle` was supplied in the request. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentCreateResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list governing who can interact with this agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the app this agent belongs to (`dap_...`). + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the agent was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Default AI model the agent uses when no model is specified at runtime, e.g. `"claude-3-5-sonnet-20241022"`. `null` if not configured. + pub default_model: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address assigned to this agent for inbound email handling. `null` if not configured. + pub email: Option, + /// Agent ID (`agi_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// System prompt or persona description that shapes the agent's behavior. `null` if not set. + pub identity: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// List of config records created as part of this request's `template_bundle` install. One entry per persisted config, sorted by `key`. Omitted entirely when the request did not include a `template_bundle`. + pub installed_configs: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Unique, stable identifier for the agent within its app. `null` if not set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the agent. `null` if none was provided. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name for the agent. `null` if not set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this agent belongs to (`org_...`). `null` for agents outside an org. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Free-form label identifying the source or author of the agent, e.g. a username or service name. `null` if not set. + pub originator: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Phone number assigned to this agent for inbound SMS or voice handling. `null` if not configured. + pub phone_number: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment this agent is scoped to (`sbx_...`). `null` for agents not scoped to a sandbox. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this agent (`tea_...`). `null` if owned by a user rather than a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the agent record was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this agent (`usr_...`). `null` if owned by a team. + pub user: Option, +} + +/// An agent environment variable with its secret value masked for safe display in list and show responses. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentEnvVarMasked { + /// ID of the agent this environment variable belongs to (`agt_...`). + pub agent: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the environment variable was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional human-readable note describing the purpose of this variable. `null` if not set. + pub description: Option, + /// Environment variable ID (`anv_...`). + pub id: String, + /// Name of the environment variable as it appears in the agent's runtime. + pub key: String, + /// Redacted representation of the secret value. The last four characters are preserved; all preceding characters are replaced with `****`. Returns `****` when the value is absent or four characters or fewer. + pub masked_value: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the environment variable was last updated (ISO 8601). + pub updated_at: Option>, +} + +/// Flat list of masked environment variables belonging to an agent. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentEnvVarMaskedList { + /// Array of masked environment variable objects for the agent. + pub data: Vec, +} + +/// A single immutable snapshot of a config's content, created each time the config is saved. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ConfigVersion { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable summary of what changed in this version, as provided by the author. `null` if no description was supplied. + pub change_description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// SHA-256 digest of the raw config content encoded as `sha256:`. Uses the same algorithm as the CLI `computeContentHash` helper. `null` for versions created before this field was introduced. + pub content_hash: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this config version was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary structured metadata stored alongside this version. `null` when no extra data was provided. + pub data: Option>, + /// Config version ID (`cfv_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) that owns this config version. `null` for personal configs. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sandbox ID (`sbx_...`) this version was saved under. `null` for production configs. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config version ID (`cfv_...`) for the Solution version this config version was installed from. `null` for standalone configs and legacy rows. + pub source_solution_config_version: Option, + /// Monotonically increasing integer identifying this version within the config. Starts at 1. + pub version_number: i64, +} + +/// A versioned config file owned by a team or user, representing a typed artifact such as an agent definition or API tool specification. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Config { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) associated with this config. `null` if not linked to an agent. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this config was first created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The most recently saved version of this config. `null` if the config has never been saved with content. + pub current_version: Option, + /// Config ID (`cfg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this config has been archived. Archived configs are hidden from default listings but remain accessible by ID. + pub is_archived: Option, + /// Type of config, e.g. `"Agent"` or `"APITool"`. Determines which fields and validation rules apply. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable, user-defined key used to look up this config without knowing its ID. `null` if not set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the config's content, e.g. `"text/yaml"`. `null` if not determined. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) this config belongs to. `null` for configs not scoped to an org. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Parent bundle config ID (`cfg_...`). Present only for configs that are children of a bundle; `null` otherwise. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID (`cfg_...`) of the solution config this config was imported with. `null` if the config was not imported via a solution. + pub parent_solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Raw file content as a string. Populated only for system configs; `null` for user-owned configs. + pub raw_content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Path of this config relative to its parent bundle root. Present only for bundle children; `null` otherwise. + pub relative_path: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sandbox identifier this config belongs to. `null` for production configs. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`tea_...`) that owns this config. `null` for personal (user-scoped) configs. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this config was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) who owns this config. `null` for team-scoped configs. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Logical path uniquely identifying this config within its team, e.g. `"agents/my-agent.yaml"`. `null` for configs without an explicit path. + pub virtual_path: Option, +} + +/// A portable export bundle for an agent, containing everything needed to re-deploy it in another workspace or environment. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentExport { + /// Ordered list of config file objects that the agent depends on. Included in full so the import can recreate all dependencies without additional requests. + pub configs: Vec, + /// The agent template definition as a structured map. Pass this directly to the import endpoint to recreate the agent. + pub template: std::collections::BTreeMap, +} + +/// A single actionable item in an agent's health or setup checklist, carrying the structured data needed to render the item and deep-link to the resolution flow. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentHealthAction { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent this action is scoped to (`agt_...`). `null` for org-level actions. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the application this action is associated with (`app_...`). `null` when not app-scoped. + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this health action was first created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// IDs of other health actions that must reach `"completed"` status before this action can be started. Empty array when there are no dependencies. + pub depends_on: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Longer Markdown-formatted explanation of what the action requires and why. `null` if not provided. + pub description: Option, + /// Health action ID (`aha_...`). + pub id: String, + /// Category of action to take. One of `"env_var"` (set a secret), `"install"` (complete an agent installation, e.g. a GitHub App), `"custom"` (agent-defined step), or `"integration"` (authorize an OAuth-backed MCP server integration). + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the verifier last ran for this action (ISO 8601). `null` until the verifier has been invoked at least once. + pub last_verified_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable output from the most recent verifier run. `null` if the verifier has not run yet. + pub last_verifier_message: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this action is associated with (`org_...`). `null` when not org-scoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Kind-specific structured data used to construct the deep-link for this action. For `"env_var"` actions includes `key` and `scope`; for `"install"` actions includes `installation_kind`; for `"integration"` actions includes `mcp_server_ref`, and when resolvable also includes `provider`, `integration_id` for OAuth handoff, and `connection_status` (`"connected"`, `"disconnected"`, or `"token_expired"`). Empty object `{}` when no additional parameters are needed. + pub params: Option>, + /// `true` if this action must be completed before the agent is considered fully operational and counts toward the blocking checklist progress bar. + pub required: bool, + /// Display order within the same `source` group. Lower values appear first. + pub sort_order: i64, + /// Lifecycle stage that produced this action. One of `"setup"` (post-install checklist item) or `"health"` (probe-detected issue). + pub source: String, + /// Current resolution state. One of `"pending"` (not yet completed), `"completed"` (resolved), `"skipped"` (dismissed by the user), or `"degraded"` (completed but the verifier is reporting a warning). + pub status: String, + /// Short display label for this action, intended for use as a checklist item heading. + pub title: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this health action was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Configuration for the action's verifier step. Contains at minimum a `type` field that indicates which verification affordance to render. Server-internal fields are stripped before this is returned. + pub verify_config: Option>, +} + +/// Aggregate health profile for an agent, summarizing its current operational status, score, and the full list of setup and health actions. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentHealth { + /// Timestamps for the agent's most recent and next scheduled activity, used to surface last-run and upcoming-run information. + pub activity: std::collections::BTreeMap, + /// The agent this health profile describes. + pub agent: Agent, + /// When the health profile was last computed (ISO 8601). + pub checked_at: chrono::DateTime, + /// Renderable health check results. Each object includes at minimum `key`, `label`, `status`, and `summary` fields. + pub checks: Vec>, + /// Action counts broken down by dependency area and resolution status, used to render progress indicators per category. + pub counts: std::collections::BTreeMap, + /// All actionable items tracked for this agent, including both `"setup"` items (post-install checklist) and `"health"` items (probe-detected issues). Sorted by `(source, sort_order, id)`. Use each item's `params` field to construct deep-links that route the user to the correct resolution flow. + pub health_actions: Vec, + /// Recent execution metrics for the agent, including run counts and failure counts over a recent time window. + pub recent: std::collections::BTreeMap, + /// Normalized health score from `0` (fully degraded) to `100` (fully healthy), derived from the weight and status of all health actions. + pub score: i64, + /// Overall health status of the agent. One of `"ok"`, `"warning"`, or `"critical"`. + pub status: String, +} + +/// Paginated list of agent objects. Use the pagination fields to traverse multiple pages of results. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentListResponse { + /// Array of agent objects for the current page. + pub data: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` when a subsequent page of results exists. + pub has_next: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` when a previous page of results exists. + pub has_prev: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current page number, starting at 1. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of agents returned per page. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of agents matching the query across all pages. + pub total_entries: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of pages available given the current `page_size`. + pub total_pages: Option, +} + +/// Controls visibility and canonical recipient selection for routine-emitted messages. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct MessagePolicy { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Required and non-empty for private visibility. Sources are additive. Routine owner includes the agent owner and optional user co-owner. + pub recipients: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message visibility. One of `default` or `private`. + pub visibility: Option, +} + +/// LLM invocation settings for a routine or chain step. When present, overrides the agent-level model selection. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct LLMConfig { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Provider-prefixed model identifier for this routine or step, e.g. `"openrouter/anthropic/claude-sonnet-latest"`. When omitted, the agent's default model is used. + pub model: Option, +} + +/// Configuration for a preset routine handler. Controls the agent's behavior, session persistence, and model selection for a given routine or chain step. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PresetConfig { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Custom task or behavior instructions for the preset (max 10,000 chars). + pub instructions: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// LLM invocation settings (e.g. a `model` override for this routine/step). + pub llm: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Session mode: `stateless` (default, new session per trigger) or `session` (find-or-create a persistent session scoped by `session_scope`). + pub session_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `session_mode` is `session`, controls session scoping: `per_user` (default), `per_key`, `per_org`, or `global`. + pub session_scope: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// IDs of structured message templates that constrain the agent's responses to predefined structured formats. + pub structured_message_template_ids: Option>, +} + +/// An agent routine defines a reusable handler — script, preset, or chain — that runs in response to events or on a schedule. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentRoutine { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for the routine. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions` (`"read"`, `"invoke"`, or `"assign"` — an `"assign"` grant names the agents or orgs that may be handed this routine's embedded work items). `null` when no ACL restrictions are applied and the routine is accessible to all members of its scope. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this routine (`agi_...`). + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Application that scopes this routine (`dap_...`). + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the Config record that backs this routine's configuration (`cfg_...`). `null` when the routine is not config-backed. + pub config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this routine was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional description of what this routine does. `null` when not set. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Additional configuration controlling how the event trigger is matched or filtered. Shape depends on `event_type`. `null` when not configured. + pub event_config: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Platform event type that triggers this routine, e.g. `"agentroutine.invoked"`. `null` for schedule-only routines. + pub event_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Execution strategy for this routine. One of `"workflow_graph"`, `"script"`, `"preset"`, or `"chain"`. + pub handler_type: Option, + /// Routine ID (`arn_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the AgentRoutineTemplate Config this routine was last provisioned or updated from (`cfg_...`). `null` for hand-built routines. + pub last_applied_template_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Unique human-readable key used to look up this routine without knowing its ID. `null` when not set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Visibility and explicit recipient selection for messages emitted by this routine. + pub message_policy: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to this routine. `null` when not set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable name for the routine. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved preset configuration when `handler_type` is `"preset"`. `null` for other handler types. + pub preset_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Name of the preset invoked when `handler_type` is `"preset"`. `null` for other handler types. + pub preset_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Cron expression controlling when the routine fires on a schedule. `null` for event-only routines. + pub schedule: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Inline script body executed when `handler_type` is `"script"`. `null` for other handler types. + pub script: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lifecycle status of the routine. One of `"draft"`, `"active"`, or `"paused"`. Only `"active"` routines respond to triggers. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Ordered list of chain steps (present when handler_type is "chain"). Each step is a plain map with handler_type, optional body fields (preset_name / preset_config / script / config), and step-local plumbing (name, inputs, output_key, on_error). + pub steps: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Execution context in which runs are created. One of `"event"` (background job) or `"chat_session"` (interactive session). Defaults to `"event"`. + pub trigger_context: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this routine was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional co-owner user (`usr_...`). When set, that user shares view/modify/delete authority on this routine without administering the parent agent. `null` when not set. Never inferred from the caller — only present when explicitly provided on create/update. + pub user: Option, +} + +/// List of agent routine objects belonging to a given agent. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentRoutineListResponse { + /// Array of agent routine objects. + pub data: Vec, +} + +/// Contract-defined values for AgentRoutineRunDeliveryStatus. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum AgentRoutineRunDeliveryStatus { + /// The not_requested wire value. + #[serde(rename = "not_requested")] + NotRequested, + /// The pending wire value. + #[serde(rename = "pending")] + Pending, + /// The delivered wire value. + #[serde(rename = "delivered")] + Delivered, + /// The failed wire value. + #[serde(rename = "failed")] + Failed, +} + +/// Contract-defined values for AgentRoutineRunDeliveryType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum AgentRoutineRunDeliveryType { + /// The none wire value. + #[serde(rename = "none")] + None, + /// The thread wire value. + #[serde(rename = "thread")] + Thread, + /// The reply wire value. + #[serde(rename = "reply")] + Reply, +} + +/// Normalized destination and status for an agent routine run's final-result delivery. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentRoutineRunDelivery { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When delivery completed successfully (ISO 8601). + pub delivered_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the message created by a successful delivery (`msg_...`). + pub delivered_message: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable public error code for the most recent failed delivery attempt. + pub last_error: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Source message ID (`msg_...`) when the delivery is a reply. + pub message: Option, + /// Current delivery lifecycle status. + pub status: AgentRoutineRunDeliveryStatus, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Destination thread ID (`thr_...`) when delivery was requested. + pub thread: Option, + #[serde(rename = "type")] + /// Normalized delivery mode. + pub type_: AgentRoutineRunDeliveryType, +} + +/// Execution state of the background worker processing a routine run. Reflects the current job status and retry progress. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct WorkerStatus { + /// Number of times the worker has been attempted so far. `0` means the job has been enqueued but not yet started. + pub attempt: i64, + /// Maximum number of attempts the worker is allowed before the job is marked `"discarded"`. + pub max_attempts: i64, + /// Current execution state of the worker. One of `"queued"`, `"executing"`, `"retrying"`, `"completed"`, `"discarded"`, or `"cancelled"`. + pub status: String, +} + +/// A single execution of an agent routine, capturing its status, inputs, outputs, and timing. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentRoutineRun { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for the run. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the run is accessible to all members of its scope. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns the parent routine (`agi_...`). + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Application that scopes this run (`dap_...`). + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this run was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Normalized final-result delivery destination and its current delivery status. + pub delivery: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total wall-clock time the run took to execute, in milliseconds. `null` while the run is still in progress. + pub duration_ms: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the platform event that triggered this run. `null` for manually invoked runs. + pub event_id: Option, + /// Routine run ID (`arr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to this run. Empty object when no metadata was set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Invoke-time map of symbolic participant references to agent IDs. `null` when no participants were supplied. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Input payload delivered to the routine when this run was triggered. Empty object when no payload was provided. + pub payload: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Output produced by the routine after execution. `null` while the run has not yet completed. + pub result: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent routine that produced this run (`arn_...`). + pub routine: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current execution status. One of `"pending"`, `"running"`, `"completed"`, `"failed"`, `"skipped"`, or `"cancelled"`. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Validated structured output extracted from `result` when the routine uses an AgentMessageSchema. `null` if the routine does not use a schema or the run has not completed. + pub structured_response: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this run was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Background worker status. `null` when no worker job is associated with this run. + pub worker: Option, +} + +/// Cursor-paginated list of agent routine run objects, ordered by creation time descending. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentRoutineRunListResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass as the after-cursor parameter to fetch the next page of runs. `null` when no later results exist. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass as the before-cursor parameter to fetch the page of runs that precede this one. `null` when no earlier results exist. + pub before_cursor: Option, + /// Array of agent routine run objects for the current page. + pub data: Vec, +} + +/// A scheduled task created by an agent. Supports one-time and recurring (cron-based) execution patterns. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentSchedule { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this schedule (`agi_...`). + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the application the schedule belongs to (`dap_...`). + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the schedule was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Standard cron expression defining the recurrence pattern (e.g. `"0 9 * * 1"`). Present only when `schedule_type` is `"recurring"`. `null` for one-time schedules. + pub cron_expression: Option, + /// Schedule ID (`asc_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The task description the agent will execute when this schedule fires. + pub instructions: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// UTC datetime of the most recent successful execution. `null` if the schedule has never run. + pub last_run_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of times a recurring schedule may fire before automatically transitioning to `"completed"`. `null` means no limit. + pub max_runs: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value pairs attached to the schedule by the agent. Not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// UTC datetime of the next planned execution. `null` if the schedule has completed, been cancelled, or has not yet been computed. + pub next_run_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of times this schedule has fired. + pub run_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Determines how the schedule repeats. `"once"` fires a single time at `scheduled_at` then transitions to `"completed"`. `"recurring"` fires on the `cron_expression` and reschedules automatically. + pub schedule_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The exact UTC datetime at which a one-time schedule fires. Present only when `schedule_type` is `"once"`. `null` for recurring schedules. + pub scheduled_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current lifecycle status of the schedule. One of `"active"` (will fire as planned), `"paused"` (temporarily suspended), `"completed"` (has run its last execution), `"cancelled"` (manually stopped), or `"expired"` (past its valid window). + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Thread ID (`thr_...`) this schedule is bound to. When set, the scheduled task is delivered into the thread rather than creating a new session. `null` for session-based schedules. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// IANA timezone name used to interpret the cron expression or `scheduled_at` (e.g. `"America/New_York"`). Defaults to `"Etc/UTC"`. + pub timezone: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the schedule was last modified (ISO 8601). + pub updated_at: Option>, +} + +/// A durable agent session record representing a single AI task execution. Tracks status, trajectory, result, and any inbox messages delivered to the session. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentSession { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this session (`agi_...`). + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the session reached a terminal state (`"completed"`, `"failed"`, or `"cancelled"`). `null` if still in progress. + pub completed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the session was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable error message describing why the session failed. `null` unless `status` is `"failed"`. + pub error: Option, + /// Session ID (`ase_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Ordered list of messages delivered to the session's inbox while it was in the `"waiting"` state. Each entry includes `id`, `role`, `content`, `sender_id`, `sender_type`, `sent_at`, and `metadata`. + pub inbox: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The task the agent is instructed to perform in this session. + pub instructions: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` if this session was created by the platform internally (e.g. by a schedule or health action) rather than by a user or API caller. + pub is_system_session: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of tool calls the agent may make within a single turn. Defaults to `25`. + pub max_runs_per_turn: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of tokens the session may consume across all turns before being terminated. Defaults to `20000`. + pub max_tokens: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of agent turns (LLM calls) allowed before the session is forcibly terminated. Defaults to `100`. + pub max_turns: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value pairs attached to the session. Not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional human-readable label for the session. `null` when not set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Structured output produced by the session on successful completion. Shape is agent-defined. `null` while the session is still running or if it failed. + pub result: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the session began executing. `null` if still `"pending"`. + pub started_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current execution status. One of `"pending"` (queued, not yet started), `"running"` (actively executing), `"waiting"` (paused for an inbox message or external event), `"completed"` (finished successfully), `"failed"` (terminated with an error), or `"cancelled"` (manually stopped). + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the trajectory that records the full message history for this session (`trj_...`). `null` until the session has started. + pub trajectory: Option, +} + +/// Paginated list response containing an array of agent session objects. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentSessionListResponse { + /// Array of agent session objects for the current page. + pub data: Vec, +} + +/// A skill enabled on an agent, linking the agent to a skill configuration. Controls which capabilities the agent has access to. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentSkill { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent this skill is attached to (`agi_...`). + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the application this skill belongs to (`dap_...`). + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the root skill config record that defines this skill's behavior (`cfg_...`). + pub config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the skill was added to the agent (ISO 8601). + pub created_at: Option>, + /// Skill ID (`ask_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional instruction text that overrides the default skill instructions for this specific agent. `null` when no override is set. + pub instruction: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent template config from which this skill was last provisioned or updated (`cfg_...`). `null` if the skill was not provisioned from a template. + pub last_applied_template_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value pairs attached to the skill. Not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether the skill is currently in use. `"active"` means the agent will use this skill during sessions. `"inactive"` means it is disabled but not deleted. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the skill was last modified (ISO 8601). + pub updated_at: Option>, +} + +/// Paginated list response containing an array of agent skill objects. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentSkillList { + /// Array of agent skill objects for the current page. + pub data: Vec, +} + +/// A tool attached to an agent, defining a capability the agent can invoke during a conversation or task run. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentTool { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent this tool belongs to (`agi_...`). + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the application that owns this tool (`dap_...`). + pub app: Option, + #[serde(rename = "async")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` when the tool executes asynchronously and returns a task handle rather than an immediate result. + pub async_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Provider-specific configuration for the built-in tool. Present only when `kind` is `"builtin"`. Shape varies by `builtin_tool_key`. + pub builtin_tool_config: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Registry key identifying the built-in tool implementation. Present only when `kind` is `"builtin"`. + pub builtin_tool_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the config record (`cfg_...`) containing this tool's full configuration. `null` for inline-only tools. + pub config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the tool was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Description of what the tool does, passed to the LLM as part of the tool definition. Resolved from the built-in registry for `kind: "builtin"` tools. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Execution handler type. One of `"http"`, `"script"`, or `"builtin"`. + pub handler_type: Option, + /// Tool ID (`atl_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional system-level instruction appended to the agent prompt when this tool is active. + pub instruction: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Tool kind. One of `"builtin"`, `"custom"`, or `"mcp"`. + pub kind: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the AgentToolTemplate config (`cfg_...`) this tool was last provisioned or updated from. `null` for manually created tools. + pub last_applied_template_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable, user-defined identifier for this tool within the agent. Unique per agent. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the tool. Not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable name of the tool as exposed to the LLM. Resolved from the built-in registry for `kind: "builtin"` tools. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Per-instance namespace prepended to LLM-facing tool names for built-in tools that support multiple instances per agent. `null` when not applicable. + pub name_prefix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// JSON Schema object describing the tool's input parameters as presented to the LLM. + pub parameters: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the config record (`cfg_...`) storing the tool's parameter schema. `null` when parameters are defined inline. + pub parameters_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current status of the tool. One of `"active"` or `"disabled"`. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the tool was last modified (ISO 8601). + pub updated_at: Option>, +} + +/// Paginated list response containing the tools attached to an agent. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentToolListResponse { + /// Array of agent tool objects returned for the current request. + pub data: Vec, +} + +/// One field-level diff entry within an agent upgrade change, describing how a single field will change. +/// `baseline` and `locally_edited` are populated only for `agent_base` entries; child resource entries (tools, routines, skills, computers) carry only `field`, `old`, and `new`. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentUpgradeFieldChange { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Value that was set by the last-applied template version (pinned baseline). Populated only on `agent_base` field changes. `null` when no baseline is available (legacy agent or deleted version). + pub baseline: Option, + /// Name of the field that will change, e.g. `"name"` or `"identity"`. + pub field: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` when the agent's current value differs from `baseline`, indicating a local edit that this upgrade will overwrite. `false` when the current value matches the baseline. `null` when `baseline` is unavailable. Populated only on `agent_base` field changes. + pub locally_edited: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Incoming value the field will be set to after the upgrade (string, number, boolean, or `null`). + pub new: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current value of the field before the upgrade (string, number, boolean, or `null`). + pub old: Option, +} + +/// One child-resource change produced by an agent upgrade, describing the action to be taken on a single resource. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentUpgradeChange { + /// The operation that will be performed. One of `"add"`, `"update"`, `"remove"`, or `"noop"`. + pub action: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Description of the child resource this change touches, when one is set. `null` when no description is available. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Field-level diff entries for this change. Populated only when `action` is `"update"`; empty or absent for `add`, `remove`, and `noop` entries. + pub field_changes: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Public ID of the existing resource being updated or removed (e.g. `atl_...`, `arn_...`). `null` for `add` entries. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lookup key of the resource derived from its source template. `null` when the template has no lookup key. + pub key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing name of the child resource this change touches (tool/routine/skill/computer name, or builtin tool key for unnamed builtin tools). Falls back to the source template's name. `null` for the synthetic `agent_base` entry. + pub name: Option, + /// Summary of the parent AgentTemplate config (`cfg_...`) being applied in this upgrade. + pub parent_template_config: UpgradeTemplateSummary, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resource-type-specific identity details. Tools: `tool_type`, `builtin_tool_key`, `name_prefix`, `handler_type`, `instruction`. Routines: `handler_type`, `preset_name`, `event_type`, `schedule`, `trigger_context`. Skills: `instruction`. Computers: `region`. Only populated keys are present; `null` when nothing is known. + pub resource: Option>, + /// Type of the child resource being changed. One of `"agent"`, `"tool"`, `"routine"`, `"skill"`, or `"computer"`. + pub resource_type: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Summary of the specific child template config (`cfg_...`) that defines this resource. `null` when no source template is resolvable. + pub source_template_config: Option, +} + +/// Aggregate counts of each change type produced by an agent upgrade diff. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentUpgradeSummary { + /// Number of child resources that will be created by this upgrade. + pub adds: i64, + /// Number of child resources with no changes in this upgrade. + pub noops: i64, + /// Number of child resources that will be removed by this upgrade. + pub removes: i64, + /// Number of child resources that will be updated by this upgrade. + pub updates: i64, +} + +/// The computed diff and outcome of an agent upgrade operation, including the full list of per-resource changes. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentUpgradeResult { + /// Ordered list of per-resource changes that will be (or were) applied by this upgrade. + pub changes: Vec, + /// `true` when the request was a dry run and no changes were persisted to the agent. + pub dry_run: bool, + /// Upgrade mode that was used. One of `"full"` (apply all changes) or `"review"` (require fingerprint confirmation). + pub mode: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque fingerprint of the computed diff. Pass this value back as `review_fingerprint` to confirm and apply a `"review"` mode upgrade. + pub review_fingerprint: Option, + /// Outcome of the upgrade. `"ready"` for a dry-run (no changes applied); `"upgraded"` when the upgrade was committed. + pub status: String, + /// Aggregate counts of adds, updates, removes, and noops across all child resources. + pub summary: AgentUpgradeSummary, +} + +/// Response returned by the agent upgrade endpoint, combining the updated agent, its source Solution and template, and the full upgrade diff. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AgentUpgradeResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The agent after the upgrade has been applied. `null` for dry-run requests where no changes were persisted. + pub agent: Option, + /// Summary of the parent Solution the agent was upgraded from. + pub solution: SolutionSummary, + /// Summary of the AgentTemplate config (`cfg_...`) that was selected for this upgrade. + pub template: UpgradeTemplateSummary, + /// Full upgrade diff including status, mode, dry-run flag, summary counts, and per-resource change list. + pub upgrade_result: AgentUpgradeResult, +} + +/// A versioned artifact produced or managed by an agent, such as a generated file, report, or code output. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Artifact { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that produced this artifact (`agt_...`). `null` if not agent-produced. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the current version's file, e.g. `"text/csv"` or `"image/png"`. `null` if no file is attached. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the artifact was first created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the current (latest published) artifact version (`artv_...`). `null` if no version has been published. + pub current_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional longer description of the artifact's contents or purpose. `null` if not set. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Storage file ID for the current version (`fil_...`). `null` if no file is attached. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the current version's file, e.g. `"output.csv"`. `null` if no file is attached. + pub file_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short-lived signed URL for downloading the current version's file. `null` if no file is attached. + pub file_url: Option, + /// Artifact ID (`art_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Image source metadata for rendering the current version's file inline. Present only when `content_type` starts with `"image/"`. `null` otherwise. + pub image_source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable name for the artifact, e.g. `"Q2 Report"`. `null` if not set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this artifact belongs to (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the sandbox environment associated with this artifact. `null` if not sandbox-scoped. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this artifact (`tea_...`). `null` if not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread in which this artifact was created (`thr_...`). `null` if not thread-scoped. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the artifact record was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this artifact (`usr_...`). `null` if not user-scoped. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current version number of the artifact. Increments each time a new version is published. + pub version: Option, +} + +/// A processed variant of a media item, such as the original upload or a resized thumbnail, including a signed download URL resolved at request time. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct MediaVariant { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of this variant's file (e.g., `"image/jpeg"`, `"video/mp4"`). `null` if the file is not loaded. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this variant was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file that backs this variant (`fil_...`). + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the uploaded file for this variant. `null` if the file is not loaded. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of this variant in pixels. `null` if not recorded. + pub height: Option, + /// Media variant ID (`mvr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types. + pub image_source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this variant was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed download URL for this variant, resolved at request time. `null` if the file is unavailable. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier for this variant's processing tier. Common values include `"original"` (the unmodified upload) and `"thumbnail"` (a resized preview). + pub variant_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of this variant in pixels. `null` if not recorded. + pub width: Option, +} + +/// A rich attachment associated with a message, such as a file, scraped link, artifact, task, media item, or inline action. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Attachment { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the attached file, e.g. `"image/png"` or `"application/pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the attached file, e.g. `"report.pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height in pixels of the media item. Present on `media` type only. `null` otherwise. + pub height: Option, + /// Unique identifier for this attachment within the message. + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise. + pub image_height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise. + pub image_source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise. + pub image_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise. + pub image_width: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The media category, e.g. `"video"` or `"audio"`. Present on `media` type only. `null` otherwise. + pub media_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the media item. Present on `media` type only. `null` otherwise. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types. + pub object: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types. + pub title: Option, + #[serde(rename = "type")] + /// The attachment type. One of `"file"`, `"scraped_link"`, `"artifact"`, `"task"`, `"media"`, `"action"`, or `"chart"`. Determines which additional fields are present. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise. + pub variants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise. + pub version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width in pixels of the media item. Present on `media` type only. `null` otherwise. + pub width: Option, +} + +/// A platform user account. Represents a human or system actor that can own threads, belong to an organization, and interact with the API. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct User { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the user. `null` if not set. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app. + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the user's app. `null` when the app association was not preloaded by the caller. + pub app_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address of the user. + pub email: Option, + /// User ID (`usr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` if this account is an internal system user rather than a human. System users are created automatically by the platform. + pub is_system_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the user. Defaults to an empty object. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full display name of the user. `null` if the user has not set a name. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Role of the user within their organization. One of `"admin"`, `"member"`, or `"viewer"`. `null` when the user is not a member of any organization. + pub org_role: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller. + pub org_slug: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller. + pub sandbox_name: Option, +} + +/// Credential bundle returned after a successful authentication exchange. Contains the access token, refresh token, and the authenticated user. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AuthTokens { + /// Number of seconds until `token` expires. After this period, use `refresh_token` to obtain a new access token. + pub expires_in: i64, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional auxiliary data associated with this authentication event, such as `onboarding_job_id` when the user is completing onboarding. `null` when no extra context is present. + pub metadata: Option>, + /// Long-lived opaque refresh token. Use this to obtain a new access token when `token` expires. + pub refresh_token: String, + /// Short-lived JWT access token. Include this value in the `Authorization: Bearer ` header for all authenticated API requests. + pub token: String, + /// Token scheme. Always `"Bearer"`. + pub token_type: String, + /// The user who authenticated. Contains the user's profile and account details. + pub user: User, +} + +/// A single execution of an automation triggered by a platform event or direct invocation. Captures the run's status, input payload, and final result. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AutomationRun { + /// ID of the app that owns this automation run (`dap_...`). + pub app: String, + /// ID of the automation that was executed (`aut_...`). + pub automation: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the automation run was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the platform event that triggered this run. `null` for directly invoked automations. + pub event_id: Option, + /// Automation run ID (`atr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Invoke-time map of symbolic participant references to agent IDs. `null` when no participants were supplied. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The input event payload that triggered this run. Structure varies by automation type. Defaults to an empty object if no payload was provided. + pub payload: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The output produced after the automation finished executing. Contains workflow-defined keys alongside any returned output. `null` if the run has not yet completed. + pub result: Option>, + /// Current execution status of the run. One of `"pending"` (queued, not yet started), `"running"` (actively executing), `"completed"` (finished successfully), `"failed"` (finished with an error), or `"cancelled"` (stopped before completion). + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this run (`tea_...`). `null` if the run is owned by a user rather than a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the automation run record was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this run (`usr_...`). `null` if the run is owned by a team rather than a user. + pub user: Option, +} + +/// A bug report or freeform feedback submission from any ArchAstro client. Bug reports are write-only for the submitting user and are not returned by any public list or show endpoint. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct BugReport { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// App ID (`dap_...`) of the developer app through which the report was submitted. + pub app: Option, + /// The client application that submitted this report. One of `"agent_network_web"`, `"cli"`, or `"developer_portal"`. + pub client: String, + /// Version string of the submitting client at the time of submission, e.g. `"1.4.2"`. + pub client_version: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional free-form JSON object providing additional context captured by the client (e.g. viewport size, active route). `null` when no context was provided. Maximum 5 KB when serialized. + pub context: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the bug report was submitted (ISO 8601). + pub created_at: Option>, + /// Freeform text describing the issue or feedback, as entered by the user. Up to 10,000 characters. + pub description: String, + /// Bug report ID (`bgr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) scoping this report. `null` when the user's account is not part of an organization. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sandbox ID (`dsb_...`) active at submission time. `null` when the report was not submitted from a sandbox context. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`tem_...`) of the team the submitting user belonged to at submission time. `null` when the user had no active team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the bug report record was last modified (ISO 8601). + pub updated_at: Option>, +} + +/// A single callable tool within a builtin tool catalog entry. Represents one discrete function an agent can invoke. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct BuiltinTool { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable explanation of what the tool does. Surfaced to the agent as part of tool selection context. `null` when no description has been defined. + pub description: Option, + /// Machine-readable name of the tool as it is registered with the agent runtime, e.g. `"web_search"` or `"github_create_issue"`. + pub name: String, +} + +/// A catalog entry describing a category of platform-provided (builtin) tools that can be enabled for an agent. Each entry groups one or more individual tools under a shared key, label, and configuration schema. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct BuiltinToolCatalogEntry { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// JSON Schema object describing the configuration options for this tool category. Clients should use this schema to render and validate configuration forms before submitting. `null` when no configuration is needed. + pub config_schema: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short prose description of what this tool category does. Suitable for display in setup UIs. `null` when no description has been defined. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Additional guidance surfaced to the agent at runtime when this tool category is enabled. `null` when no custom instruction is set. + pub instruction: Option, + /// Unique slug identifying this tool category, e.g. `"web_search"` or `"github"`. + pub key: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name for the tool category, e.g. `"Web Search"`. `null` when no label has been assigned. + pub label: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Controls whether multiple instances of this tool category may be enabled simultaneously. `"namespaced"` — multiple instances allowed; each must carry a `name_prefix` to distinguish them. `"passthrough"` — multiple instances allowed without a `name_prefix`; names are derived from the underlying source. `null` — single-instance only. + pub multi_instance_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// List of integration provider slugs that can back this tool category, e.g. `["github", "gitlab"]`. Empty when the tool is provider-agnostic. + pub providers: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether enabling this tool category requires the user to connect a third-party integration. `true` means at least one active integration of the appropriate type must exist before the tool can be used. + pub requires_integration: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Internal type identifier used by the platform server when registering these tools. `null` for client-side-only tool categories. + pub server_tool_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of individual tool definitions included in this category. Each entry describes a single callable tool with its own name and description. + pub tools: Option>, +} + +/// Empty acknowledgement payload returned by channel message handlers that produce no data. The wire envelope is `{"status": "ok", "response": {}}`. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ChannelAck {} + +/// A participant in a chat thread, which may be either a human user or an AI agent. Exactly one of `user` or `agent` is populated depending on `type`. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ChatMember { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full agent object for this member. Populated when `type` is `"agent"`; `null` for user members. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Role of this member within the thread. Common values are `"owner"` and `"member"`. `null` when the membership type is not applicable. + pub membership_type: Option, + #[serde(rename = "type")] + /// Kind of participant. One of `"user"` (a human user) or `"agent"` (an AI agent). + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full user object for this member. Populated when `type` is `"user"`; `null` for agent members. + pub user: Option, +} + +/// A compact reaction record embedded in a message's `reactions` array, representing a single user's reaction to a message. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct MessageReaction { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Type-specific reaction data. For `"emoji_reaction"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `"👍"`). + pub payload: Option>, + #[serde(rename = "type")] + /// Reaction type identifier. Currently always `"emoji_reaction"` for emoji-based reactions. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Public ID of the user who added the reaction (`usr_...`). + pub user: Option, +} + +/// Contract-defined values for MessageAgentMode. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum MessageAgentMode { + /// The cli wire value. + #[serde(rename = "cli")] + Cli, + /// The embedded wire value. + #[serde(rename = "embedded")] + Embedded, +} + +/// Contract-defined values for MessageVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum MessageVisibility { + /// The default wire value. + #[serde(rename = "default")] + Default, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Message { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry. + pub actors: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path. + pub agent_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments. + pub attachments: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread. + pub branched_thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Text content of the message. `null` for messages that contain only attachments. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the message was posted (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this message has at least one reply. Only present when explicitly requested or computed by the server. + pub has_replies: Option, + /// Message ID (`msg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one. + pub idempotency_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages. + pub is_deleted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users. + pub legacy_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization that owns this message (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded. + pub reactions: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display hint for how the message should be rendered. One of `"reply"`, `"direct"`, or `"inline"`. `null` for user-authored messages, which are always rendered as standard replies. + pub rendering_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message. + pub replies: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response. + pub replies_after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response. + pub replies_before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of direct replies to this message. Only present when explicitly requested or computed by the server. + pub reply_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded. + pub reply_to: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages. + pub root_message_id: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread. + pub thread: Option, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees. + pub visibility: Option, +} + +/// A team within an organization, used to group users and agents and scope resources like configs, agents, and tasks. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Team { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list governing visibility and join permissions for this team. `null` when no ACL restrictions are applied and the team inherits default access rules. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer application this team belongs to (`dap_...`). `null` if the team is not scoped to an app. + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Aggregated badge counts for the team, keyed by category. `null` when badge data is not loaded. + pub badges: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this team was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of the team's purpose. `null` if not set. + pub description: Option, + /// Team ID (`tem_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The authenticated viewer's role on this team. One of `"owner"`, `"admin"`, or `"member"`. `null` if the viewer is not a member. + pub membership_status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to this team. Returns an empty object when no metadata has been set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the team. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this team belongs to (`org_...`). `null` if the team is not org-scoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this team is scoped to (`dsb_...`). `null` outside sandbox contexts. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL-safe slug for the team, derived from the team name. `null` if not set. + pub slug: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this team was last updated (ISO 8601). + pub updated_at: Option>, +} + +/// Configuration settings for a thread that control AI agent behavior and other thread-level preferences. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ThreadSettings { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured. + pub agent_enabled: Option, +} + +/// Contract-defined alternatives for ThreadCreator. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ThreadCreator { + /// Variant1 union variant. + Variant1(String), + /// Variant2 union variant. + Variant2(Value), +} + +/// Contract-defined values for ThreadVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ThreadVisibility { + /// The team wire value. + #[serde(rename = "team")] + Team, + /// The restricted wire value. + #[serde(rename = "restricted")] + Restricted, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// A chat thread, representing a conversation channel that can be owned by a user, team, or agent and may contain messages, participants, and AI agent activity. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Thread { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this thread (`agt_...`). `null` for user-owned or team-owned threads. + pub agent_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the thread was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User who created this thread. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if the creator is unknown. + pub creator: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional description or purpose statement for the thread. `null` if not set. + pub description: Option, + /// Thread ID (`thr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this thread operates as a channel — a multi-member broadcast-style conversation. + pub is_channel: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this is the default thread for its owner. Each user or team has at most one default thread. + pub is_default: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this thread is ephemeral and may be deleted automatically after a period of inactivity or when its TTL expires. + pub is_transient: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this thread is hidden from public discovery. Unlisted threads are accessible only to direct participants. + pub is_unlisted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Application-defined stable key that uniquely identifies the thread within its scope. Useful for idempotent creation. `null` if not set. + pub key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Thread subtype: `"standard"` for ordinary threads, `"slack_mirror"` for the membership-strict mirror of a Slack channel, `"slashwork_mirror"` for the membership-strict mirror of a Slashwork group. Read-only — derived server-side at creation, never accepted from params. + pub kind: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the most recent message was posted in this thread, falling back to the thread's creation time if it has no messages. Always populated on thread list endpoints (which order by it, after default threads); `null` on endpoints that don't compute activity enrichment. + pub last_activity: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Single-line snippet of the most recent message's text content (first non-empty line, truncated to 140 characters). Populated on thread list endpoints alongside `last_activity`; `null` when the thread has no messages, the latest message has no text content (e.g. attachment-only), or the endpoint doesn't compute activity enrichment. + pub last_message_preview: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the sender of the most recent message — the same message `last_message_preview` snippets. Populated on thread list endpoints; `null` when the thread has no messages or the endpoint doesn't compute activity enrichment. + pub last_message_sender: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the thread. Shape is application-defined; `null` if no metadata has been set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether the authenticated user has muted notifications for this thread. `true` suppresses all notification delivery. + pub muted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this thread belongs to (`org_...`). `null` for threads outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The message that spawned this thread as a sub-thread. `null` for top-level threads. + pub parent_message: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of participant user IDs (`usr_...`) who are members of this thread. + pub participant: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Expanded participant user objects for each member of this thread. Populated only when the association is loaded. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifiers for all participants currently active in this thread. Present only when actor enrichment is requested. + pub participating_actor: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Expanded agent objects for all agents participating in this thread. Present only when agent enrichment is requested. + pub participating_agents: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The authenticated user's membership role in this thread, e.g. `"owner"`, `"member"`, or `"viewer"`. `null` if the user is not a member. + pub role: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this thread is scoped to (`dsb_...`). `null` for production threads. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Per-thread configuration settings controlling AI agent behavior for this thread. + pub settings: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL-safe slug for the thread, used in human-readable permalinks. `null` if not assigned. + pub slug: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Threads that are nested under this thread as replies to a parent message. Present only when sub-thread enrichment is requested. + pub sub_threads: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Status tags on the thread (e.g. `"blocked"`, `"needs-review"`). Edited by any thread participant via the `/threads/:thread/tags` endpoints and filterable on the thread list endpoints. Empty array if none set. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this thread (`team_...`). `null` for user-owned or agent-owned threads. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable name of the thread. `null` if no title has been set. + pub title: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Time-to-live in seconds after which the thread may be automatically cleaned up. `null` if the thread does not expire. + pub ttl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of messages in this thread that the authenticated user has not yet read. Present only when read-state enrichment is requested. + pub unread_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the thread was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who owns this thread (`usr_...`). `null` for team-owned or agent-owned threads. + pub user: Option, + /// Who can read the thread: `team` for every owning-team member, `restricted` for team-readable threads with an explicit roster, or `private` for roster-only access. + pub visibility: ThreadVisibility, +} + +/// A point-in-time snapshot of a chat room's state, including its loaded messages, member roster, and pagination cursors. Returned when loading or refreshing a thread's message list. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ChatRoomModel { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass when fetching messages newer than those in this snapshot. `null` when this snapshot already reflects the latest messages. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The agent associated with this chat room. `null` when no agent is attached. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass when fetching messages older than those in this snapshot. `null` when the beginning of the thread history has been reached. + pub before_cursor: Option, + /// Whether this thread is ephemeral. Transient threads are not retained in long-term storage and may be deleted when the session ends. + pub is_transient: bool, + /// All active members of the chat room, including both human users and agents. + pub members: Vec, + /// The page of messages currently loaded for the thread, ordered chronologically. Use `before_cursor` or `after_cursor` to page through additional history. + pub messages: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of messages that were added to the snapshot in the most recent incremental update. `null` on the initial load. + pub messages_loaded_on_last_update: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The team that owns this thread. `null` for threads scoped to an individual user rather than a team. + pub team: Option, + /// The parent thread whose message history and membership this snapshot represents. + pub thread: Thread, +} + +/// Response returned after forking a chat thread. Contains the new thread, its initial chat-room snapshot, and the owning team when applicable. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ChatForkThreadResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Initial chat-room render snapshot for the forked thread, including members and loaded messages. `null` for transient threads whose room model is suppressed. + pub chat_model: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team that owns the forked thread. Present only when the original thread was team-scoped; `null` for personal threads. + pub team: Option, + /// The newly-created thread produced by the fork operation. + pub thread: Thread, +} + +/// Response returned after loading an additional page of chat messages. Contains a refreshed chat-room snapshot with the newly-fetched messages merged in. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ChatLoadMoreMessagesResponse { + /// Updated chat-room snapshot for the thread, incorporating the newly-loaded page of messages alongside any previously loaded messages. + pub data: ChatRoomModel, +} + +/// Response returned after marking a chat thread as read. Confirms that the read marker was successfully recorded for the authenticated user. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ChatMarkThreadReadResponse { + /// Indicates whether the read marker was successfully applied. Always `true` on success; errors are returned as channel error replies rather than a `false` value here. + pub success: bool, +} + +/// Response returned when listing the messages of a joined chat thread. Contains the set of messages currently loaded for the thread. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ChatMessageListResponse { + /// Ordered array of message objects currently loaded for the thread, from oldest to newest. Use the `load_more_messages` channel message to fetch earlier pages. + pub messages: Vec, +} + +/// Response returned after successfully posting a message to a chat thread. Contains the persisted message object echoed back to the sender. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ChatPostMessageResponse { + /// The message that was created and stored. Contains the full message object including its assigned ID, author, content, and timestamps. + pub message: Message, +} + +/// The result of executing a shell command on an agent's computer environment. Contains the captured output and the process exit code. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ComputerExecResult { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The UNIX exit code returned by the process. `0` indicates success; any non-zero value indicates an error. `null` if the process did not terminate normally. + pub exit_code: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The combined stdout and stderr output produced by the command. `null` if the command produced no output. + pub output: Option, +} + +/// A facet entry grouping configs by kind, returning the kind name and the number of matching configs visible to the authenticated viewer. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ConfigKindFacet { + /// Number of configs of this kind that are visible to the authenticated viewer. Always `0` or greater. + pub count: i64, + /// The config kind identifier (e.g., `"Agent"`, `"WorkflowGraph"`). Matches the `kind` field on config objects. + pub kind: String, +} + +/// A facet entry grouping configs by their leading path segment, returning the prefix and the number of matching configs visible to the authenticated viewer. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ConfigPathPrefixFacet { + /// Number of configs whose `virtual_path` begins with this prefix that are visible to the authenticated viewer. Always `0` or greater. + pub count: i64, + /// The leading path segment of the config's `virtual_path`, always slash-terminated (e.g., `"agents/"`, `"__editor/"`). Pass this value as the `path_prefix` filter to narrow config listings. + pub prefix: String, +} + +/// Aggregated facet counts for the authenticated viewer's configs. Reports all distinct kinds and path prefixes across the full dataset, regardless of any active list filters. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ConfigFacets { + /// All distinct config kinds present in the viewer's dataset, each with its total count. Use these values to populate kind filter options. + pub kinds: Vec, + /// All distinct slash-terminated path prefixes present in the viewer's dataset, each with its total count. Use these values to populate path prefix filter options. + pub path_prefixes: Vec, +} + +/// The JSON Schema definition and sample YAML for a specific config kind, used to validate and scaffold new configs of that kind. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ConfigKindSchema { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// JSON Schema object describing the valid structure of a config of this kind. `null` when no schema has been registered for this kind. + pub json_schema: Option>, + /// The config kind identifier (e.g., `"Agent"`, `"WorkflowGraph"`). Matches the `kind` field on config objects. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// A sample YAML document illustrating a minimal valid config of this kind. `null` when no sample has been registered for this kind. + pub sample_yaml: Option, +} + +/// A context document stored within a context source. Carries metadata and size information only; retrieve the full text content via the `/content` endpoint. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ContextDocument { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this document (`agi_...`). `null` if owned by a user or team. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lowercase-hex sha256 of the document's full text, covering content only — not `title` or `metadata`. Compare it against a hash of your local copy to decide whether the document needs re-ingesting, without fetching `/content`. `null` for documents ingested before this field existed; it is not backfilled. + pub content_hash: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the document was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the backing storage file (`fil_...`) when the document is file-backed. `null` for inline documents. + pub file: Option, + /// Context document ID (`cdo_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the document. Shape varies by source type. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the context source this document belongs to (`cso_...`). + pub source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this document (`tem_...`). `null` if owned by a user or agent. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display title of the document. `null` if no title has been set. + pub title: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of lines in the document's text content. `0` if the document has no content. + pub total_lines: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total byte size of the document's text content. `0` if the document has no content. + pub total_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the document was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this document (`usr_...`). `null` if owned by a team or agent. + pub user: Option, +} + +/// The text content of a context document, optionally sliced by line or byte range. Includes totals and slice boundary fields for the requested unit. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ContextDocumentContent { + /// Text of the document. Contains the full content when no `offset`/`limit` was requested, or only the requested slice otherwise. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Zero-based exclusive index of the last byte in `content` (i.e. the slice covers bytes `start_byte..end_byte-1`). Populated only when `unit` is `"bytes"`; `null` otherwise. + pub end_byte: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// 1-indexed line number of the last line included in `content` (i.e. the slice covers lines `start_line` through `end_line` inclusive). Populated only when `unit` is `"lines"`; `null` otherwise. + pub end_line: Option, + /// Context document ID (`cdo_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The `limit` value echoed from the request. `null` when no limit was requested. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the document, such as source URL or author. `null` if no metadata was recorded. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The `offset` value echoed from the request. `null` when no offset was requested. + pub offset: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Zero-based index of the first byte included in `content`. Populated only when `unit` is `"bytes"`; `null` otherwise. + pub start_byte: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// 1-indexed line number of the first line included in `content`. Populated only when `unit` is `"lines"`; `null` otherwise. + pub start_line: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display title of the document. `null` if the document has no title set. + pub title: Option, + /// Total number of lines in the document's full content, regardless of any slice. + pub total_lines: i64, + /// Total byte size of the document's full content, regardless of any slice. + pub total_size: i64, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Slice unit used when `offset` and `limit` were provided. One of `"lines"` (default) or `"bytes"`. `null` when no slice was requested. + pub unit: Option, +} + +/// A context ingestion job that processes a context source and populates its documents. Tracks status and timing from submission through completion or failure. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ContextIngestion { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that initiated this ingestion (`agi_...`). `null` if initiated by a user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the ingestion job finished, either successfully or with a failure. `null` if still in progress. + pub completed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the ingestion was submitted (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Structured error details when the ingestion has `status: "failed"`. `null` for any other status. + pub error: Option>, + /// Context ingestion ID (`cig_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata associated with this ingestion run. Shape is caller-defined. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the context source being ingested (`cso_...`). `null` if the source has been deleted. + pub source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the ingestion job began processing. `null` if the job is still pending. + pub started_at: Option>, + /// Current processing status. One of `"pending"`, `"running"`, `"awaiting_callback"`, `"succeeded"`, or `"failed"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this ingestion (`tem_...`). `null` if owned by a user or agent. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the ingestion record was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that initiated this ingestion (`usr_...`). `null` if initiated by an agent. + pub user: Option, +} + +/// Creation-only private service enrollment response. The raw token is shown +/// once and is omitted from every read schema. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct CreatedPrivateServiceEnrollment { + /// One-time connector enrollment token. Store it immediately. + pub enrollment_token: String, + /// When the one-time enrollment token expires. + pub enrollment_token_expires_at: chrono::DateTime, + /// API field. + pub generation: i64, + /// API field. + pub id: String, + /// API field. + pub private_service: String, +} + +/// A custom object belonging to an organization. Custom objects store arbitrary structured data defined by a schema type and are scoped to an org, team, or user. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct CustomObject { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list governing read and write access to this custom object. Only returned to resource owners and privileged or organization-admin viewers; `null` for everyone else. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the custom object was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Map of field names to their current values as defined by the object's schema type. + pub fields: Option>, + /// Unique identifier for the custom object (`cobj_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this object belongs to (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// An optional stable key used to identify this object by a caller-controlled string rather than its generated ID. `null` if not set. + pub row_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment this object is scoped to (`dsb_...`). `null` for production objects. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The lookup key of the schema type that defines this object's field structure. `null` if the schema type has not been set. + pub schema_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this object (`tem_...`). `null` if the object is not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the custom object was last modified (ISO 8601). `null` if the object has never been updated after creation. + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this object (`usr_...`). `null` if the object is not user-scoped. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optimistic concurrency version of the object. Increments with each successful update; pass this value in write operations to detect conflicting changes. + pub version: Option, +} + +/// Initial authoritative snapshot returned by a custom-object channel join. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct CustomObjectJoinResponse { + /// Collision-free identifier for this browser connection. + pub connection_id: String, + /// Current materialized fields, or `null` while waiting for object creation. + pub fields: Option>, + /// Custom-object ID, or `null` while a row-key subscription waits for creation. + pub id: Option, + /// Current ephemeral collaborator presence. + pub presence: Vec>, + /// Whether the current connection may only read the object. + pub readonly: bool, +} + +/// A paginated page of custom objects returned by a list operation. Use the pagination fields to navigate through result sets. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct CustomObjectListResponse { + /// Array of custom objects for the current page. + pub data: Vec, + /// `true` if a subsequent page of results exists; `false` if this is the last page. + pub has_next: bool, + /// `true` if a preceding page of results exists; `false` if this is the first page. + pub has_prev: bool, + /// The current page number (1-indexed). + pub page: i64, + /// Maximum number of results returned per page. + pub page_size: i64, + /// Total number of custom objects matching the query across all pages. + pub total_entries: i64, + /// Total number of pages available for the current query. + pub total_pages: i64, +} + +/// Acknowledges an ephemeral custom-object presence update. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct CustomObjectPresenceAck { + /// Collision-free connection identifier assigned to this browser connection. + pub connection_id: String, +} + +/// Acknowledges that the current custom-object document reached durable storage. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct CustomObjectSaveResponse { + /// Durable optimistic-concurrency version after the save. + pub version: i64, +} + +/// Response returned after updating one or more fields on a custom object. Confirms the object that was modified and the field values that were applied. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct CustomObjectUpdateFieldsResponse { + /// The materialized object fields after the update. + pub fields: std::collections::BTreeMap, + /// ID of the custom object that was updated (`cobj_...`). + pub id: String, + /// Idempotency key acknowledged for this update. + pub operation_id: String, +} + +/// Deployment metadata. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Deployment { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Deployment environment, or `null` when it is not configured. + pub environment: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque SHA-256 fingerprint of the image reference, or `null` in local development. + pub release: Option>, +} + +/// User-visible details for a pending OAuth 2.0 device authorization. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct DeviceAuthorizationDetailsResponse { + /// Name of the client requesting authorization. + pub client_name: String, + /// Expiration time for the pending device authorization. + pub expires_at: chrono::DateTime, + /// Scopes the client is requesting. + pub scopes: Vec, +} + +/// The initial response from an OAuth 2.0 Device Authorization Grant request, containing the codes and URIs needed to complete device authentication. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct DeviceAuthorizationResponse { + /// Opaque code identifying this device authorization session. Pass this value when polling the token endpoint; do not display it to the user. + pub device_code: String, + /// Number of seconds until the `device_code` and `user_code` expire. After expiry the user must restart the authorization flow. + pub expires_in: i64, + /// Minimum number of seconds to wait between polling attempts on the token endpoint. Polling more frequently will result in a `slow_down` error. + pub interval: i64, + /// Short alphanumeric code the user must enter at `verification_uri` to authorize the device. + pub user_code: String, + /// URL the user visits to enter the `user_code` and approve the authorization request. + pub verification_uri: String, + /// Full verification URL with the `user_code` pre-filled as a query parameter. Display this as a QR code or deep link to reduce manual entry. + pub verification_uri_complete: String, +} + +/// The result of a completed OAuth 2.0 Device Authorization flow, indicating whether the user approved or denied the device's access request. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct DeviceAuthorizationStatusResponse { + /// Outcome of the device authorization request. One of `"approved"` (the user granted access) or `"denied"` (the user rejected or cancelled the request). + pub status: String, +} + +/// A file stored in the platform's object storage, with metadata and a signed URL for downloading its contents. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct StorageFile { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the app this file belongs to (`app_...`). + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the file, e.g. `"image/png"` or `"application/pdf"`. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the file was uploaded (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename as provided at upload time. + pub filename: Option, + /// File ID (`fil_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Image display metadata. Present only when `content_type` is an image type; `null` otherwise. + pub image_source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization that owns this file (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox this file is scoped to (`sbx_...`). `null` for files not associated with a sandbox. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable public URL for the file, fetchable without authentication. Present only when the file was shared (`share: true`); does not expire until sharing is disabled. Disabling and re-enabling sharing reactivates the same URL. `null` otherwise. + pub share_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Size of the file in bytes. + pub size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this file (`team_...`). `null` if not team-owned. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the file record was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short-lived signed URL for downloading the file. `null` if a URL could not be generated. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this file (`user_...`). `null` if not user-owned. + pub user: Option, +} + +/// Contract-defined values for ExtractionOutputState. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ExtractionOutputState { + /// The done wire value. + #[serde(rename = "done")] + Done, + /// The failed wire value. + #[serde(rename = "failed")] + Failed, +} + +/// A produced file tracked by an extraction. Type, size, and URL live on the file it points at. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ExtractionOutput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this output was produced (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The produced file. For a config destination this is the `Storage.File` backing the versioned config row; type, size, and URL live here. + pub file: Option, + /// Output ID (`exo_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Position of this output within the extraction's output set. + pub ordinal: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The crawled page path or document path this output came from. + pub source_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Output state. + pub state: Option, +} + +/// Contract-defined values for ExtractionFailureReason. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ExtractionFailureReason { + /// The fetch_failed wire value. + #[serde(rename = "fetch_failed")] + FetchFailed, + /// The unsupported_content wire value. + #[serde(rename = "unsupported_content")] + UnsupportedContent, + /// The extraction_failed wire value. + #[serde(rename = "extraction_failed")] + ExtractionFailed, + /// The timeout wire value. + #[serde(rename = "timeout")] + Timeout, + /// The internal_error wire value. + #[serde(rename = "internal_error")] + InternalError, +} + +/// Contract-defined values for ExtractionKind. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ExtractionKind { + /// The document wire value. + #[serde(rename = "document")] + Document, + /// The link wire value. + #[serde(rename = "link")] + Link, + /// The site wire value. + #[serde(rename = "site")] + Site, +} + +/// Contract-defined values for ExtractionState. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ExtractionState { + /// The pending wire value. + #[serde(rename = "pending")] + Pending, + /// The running wire value. + #[serde(rename = "running")] + Running, + /// The done wire value. + #[serde(rename = "done")] + Done, + /// The failed wire value. + #[serde(rename = "failed")] + Failed, +} + +/// An extraction job: yields text from a document or website into a destination namespace, without committing knowledge to an agent. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Extraction { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Owning agent (`agt_...`); `null` when not agent-scoped. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total bytes across produced storage files (a derived aggregate). + pub byte_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the extraction was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Where outputs were written: `{ kind, path_prefix }`. + pub destination: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Failure category when `state` is `failed`; `null` otherwise. + pub failure_reason: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Source file (`fil_...`) for document extraction; `null` for link/site. + pub file: Option, + /// Extraction ID (`ext_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// What is being extracted. + pub kind: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Owning organization (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of produced output files (a derived aggregate). + pub output_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Produced output files; populated only when the association is preloaded. + pub outputs: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lifecycle state of the extraction job. + pub state: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the extraction was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Source URL for link/site extraction; `null` for document. + pub url: Option, +} + +/// List response containing agent health actions for a given agent or organization. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct HealthActionListResponse { + /// Array of agent health action objects representing setup checklist items and probe-detected issues. + pub data: Vec, +} + +/// An installation representing a connection between an agent and an external service or enablement channel. Tracks configuration, lifecycle state, and any bound integration. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Installation { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this installation (`agi_...`). `null` if the installation has no agent owner. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Kind-specific configuration object for this installation. Shape depends on the `kind` value. `null` if the kind requires no configuration. + pub config: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the installation was created (ISO 8601). + pub created_at: Option>, + /// Installation ID (`cin_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Slug identifying the type of external service this installation connects to, e.g. `"enablement/github_app"` or `"integration/gmail"`. `null` if not set. + pub kind: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Caller-assigned stable identifier for this installation, used to reference it in knowledge search `source_refs`. `null` if no lookup key was provided at creation time. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the shared org- or app-level integration bound to this installation (`int_...`). `null` if no integration has been bound. + pub shared_integration: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current lifecycle state of the installation. One of `"pending"`, `"active"`, `"paused"`, or `"error"`. `"error"` indicates the installation was suspended due to a policy or compliance issue and requires attention. + pub state: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Provider-supplied status detail for this installation, set during activation or event processing. `null` if no status has been reported. + pub status_payload: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the installation record was last updated (ISO 8601). + pub updated_at: Option>, +} + +/// A supported installation kind describing a category of external service or enablement channel an agent can be connected to. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct InstallationKind { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, sources can be attached to installations of this kind to supply additional context to the agent. + pub accepts_sources: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Grouping category for UI display purposes, e.g. `"enablement"` or `"integration"`. `null` if uncategorized. + pub category: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// JSON Schema object describing the shape of the `config` parameter accepted when creating or updating an installation of this kind. `null` if the kind accepts no configuration. + pub config_schema: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short prose description of what this kind connects to and how it is used. `null` if no description is defined. + pub description: Option, + /// Unique slug identifying this installation kind, e.g. `"enablement/github_app"`, `"integration/gmail"`, or `"web/site"`. Pass this value as `kind` when creating an installation. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name for this kind, e.g. `"GitHub App"`. `null` if the kind has no label defined. + pub label: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the external provider this kind connects to, e.g. `"github"` or `"slack"`. `null` for kinds with no specific provider. + pub provider: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, this kind requires an integration to be provided (either inline or via `shared_integration`) before the installation can be activated. + pub requires_integration: Option, +} + +/// List response containing the publicly available installation kinds that can be used when configuring an agent installation. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct InstallationKindListResponse { + /// Array of installation kind objects describing the available integration types and their configuration requirements. + pub data: Vec, +} + +/// Paginated list response containing installation objects for an agent. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct InstallationListResponse { + /// Array of installation objects returned for the current page. + pub data: Vec, +} + +/// A source attached to an installation that supplies content for the agent's context. Sources are processed asynchronously after creation. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct InstallationSource { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this source (`agi_...`). `null` if the source is not agent-owned. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the installation this source belongs to (`cin_...`). `null` if the source is not attached to an installation. + pub context_installation: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the source was created (ISO 8601). + pub created_at: Option>, + /// Source ID (`cso_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata associated with this source. Shape is caller-defined. `null` if no metadata was set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent source (`cso_...`) when this source was derived from another source. `null` for top-level sources. + pub parent_source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Type-specific payload provided when the source was created. The shape depends on the `type` value. `null` if no payload was supplied. + pub payload: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current lifecycle state of this source. One of `"active"` (ingestion running normally) or `"paused"` (ingestion suspended). Note that per-run ingestion progress is tracked separately and is not exposed on this field. + pub state: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team associated with this source (`tem_...`). `null` if the source has no team association. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the conversation thread linked to this source (`thr_...`). `null` if the source is not thread-scoped. + pub thread: Option, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Slug identifying the kind of content this source provides, e.g. `"file/document"` or `"web/link"`. `null` if the type is not set. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the source record was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user associated with this source (`usr_...`). `null` if the source has no user association. + pub user: Option, +} + +/// Paginated list response containing installation source objects attached to an installation. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct InstallationSourceListResponse { + /// Array of installation source objects returned for the current page. + pub data: Vec, +} + +/// A minimal, public-safe projection of the user who sent an invite, exposed to unauthenticated recipients so they can render a join screen. +/// Only identity fields are included; sensitive fields such as email address and organization membership are omitted. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct InviteCreator { + /// User ID of the inviter (`usr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the inviter. `null` when the inviter has not set a name on their account. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture of the inviter. `null` when the inviter has no profile picture set. + pub profile_picture: Option, +} + +/// A single key-value storage entry belonging to a user. Represents one key/value pair written to a user's isolated storage namespace within an app. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct KeyValueStorageEntry { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this storage entry was first created (ISO 8601). `null` if not yet persisted. + pub created_at: Option>, + /// The string key used to store and look up this entry. + pub key: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this storage entry was last updated (ISO 8601). `null` if not yet persisted. + pub updated_at: Option>, + /// ID of the user who owns this storage entry (`usr_...`). + pub user: String, + /// The string value stored under `key` for this user. + pub value: String, +} + +/// A key-value storage entry enriched with owner information. Developer and server-to-server callers receive `user_email` and `user_name` populated; end-user (user-JWT) callers receive those fields as `null`. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct KeyValueStorageEntryWithUser { + /// When this storage entry was first created (ISO 8601). + pub created_at: chrono::DateTime, + /// The string key used to store and look up this entry. + pub key: String, + /// When this storage entry was last updated (ISO 8601). + pub updated_at: chrono::DateTime, + /// ID of the user who owns this storage entry (`usr_...`). + pub user: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address of the owning user. `null` for end-user (user-JWT) callers; populated for developer and server-to-server callers. + pub user_email: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the owning user. `null` for end-user (user-JWT) callers; populated for developer and server-to-server callers. + pub user_name: Option, + /// The string value stored under `key` for this user. + pub value: String, +} + +/// Paginated response envelope for the dual-mode key-value storage list endpoint. End-user (user-JWT) callers receive only `data`; developer and server-to-server callers also receive pagination metadata fields. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct KeyValueStorageEntryPage { + /// Array of key-value storage entries for the current page. + pub data: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether a subsequent page exists. `false` when the current page is the last page. Present only for developer and server-to-server callers. + pub has_next: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether a preceding page exists. `false` when the current page is the first page. Present only for developer and server-to-server callers. + pub has_prev: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current page number (1-indexed). Present only for developer and server-to-server callers. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of results returned per page. Present only for developer and server-to-server callers. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of storage entries matching the applied filters across all pages. Present only for developer and server-to-server callers. + pub total_entries: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of pages available given the current `page_size`. Present only for developer and server-to-server callers. + pub total_pages: Option, +} + +/// A knowledge source that ingests content into the knowledge base. Sources connect to external systems (e.g. Gmail, GitHub) and continuously or on-demand index items for search. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct KnowledgeSource { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this source (`agt_...`). `null` if owned by a human user or team. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the context installation that provisioned this source (`cin_...`). `null` when the source was created directly rather than through an installation. + pub context_installation: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this knowledge source was created (ISO 8601). + pub created_at: Option>, + /// Knowledge source ID (`cso_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to this source. Useful for storing caller-defined labels or references. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this source belongs to (`org_...`). `null` if not scoped to an org. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent knowledge source (`cso_...`) when this source was derived from another. `null` for top-level sources. + pub parent_source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Type-specific configuration object. The keys depend on the source `type`; see the create endpoint for the expected shape per type. + pub payload: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this source is scoped to (`sbx_...`). `null` outside sandbox contexts. + pub sandbox: Option, + /// Current lifecycle state of the source. One of `"active"` (ingestion running normally) or `"paused"` (ingestion suspended). + pub state: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this source (`tea_...`). `null` if owned by a user, agent, or org. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the chat thread this source is associated with (`thr_...`). `null` when not thread-scoped. + pub thread: Option, + #[serde(rename = "type")] + /// Source type identifier (e.g. `"gmail"`, `"github_activity"`). Determines the shape of `payload` and the ingestion behavior. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this knowledge source was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this source (`usr_...`). `null` if owned by a team, agent, or org. + pub user: Option, +} + +/// Describes a single knowledge source kind that can be created through the public API. Use the `type` value when creating a new knowledge source. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct KnowledgeSourceKind { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short description of what this source kind ingests and how it is used. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name for this source kind, suitable for showing in a UI. + pub label: Option, + #[serde(rename = "type")] + /// Machine-readable type identifier for this source kind (e.g. `"gmail"`, `"github_activity"`). Pass this value as `type` when creating a knowledge source. + pub type_: String, +} + +/// List response containing the knowledge source kinds available for creation via the API. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct KnowledgeSourceKindListResponse { + /// Array of knowledge source kind objects describing each creatable source type. + pub data: Vec, +} + +/// An inbox notification delivered to a recipient user. Includes type-specific render data resolved at request time. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Notification { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the recipient archived this notification. `null` if the notification has not been archived. + pub archived_at: Option>, + /// When the notification was sent (ISO 8601). + pub created_at: chrono::DateTime, + /// Notification ID (`ntf_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the recipient marked this notification read. `null` if the notification has not been read. + pub read_at: Option>, + /// Type-specific render spec resolved at request time. All types include `title`, `kind`, and `actions`; custom types may add their own keys. Notifications whose type is no longer registered render with `kind: "unknown"`. + pub rendered: std::collections::BTreeMap, + /// Current read state of the notification. One of `"unread"`, `"read"`, or `"archived"`. + pub status: String, + #[serde(rename = "type")] + /// Notification type slug, e.g. `"app_info"` for a built-in type or `"custom:deploy_complete"` for a custom type. + pub type_: String, +} + +/// A single per-channel notification preference for the authenticated viewer, scoped to a notification type and optional app. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct NotificationPreference { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// App this preference is scoped to (`app_...`). `null` indicates a system-level (no-app) slot that applies across all apps. + pub app_id: Option, + /// Delivery channel for this preference, e.g. `"email"`. The `in_app` channel is always active and never has a preference row. + pub channel: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this preference record was created (ISO 8601). + pub created_at: Option>, + /// Whether delivery over this channel is enabled for the given type-and-app combination. `false` suppresses delivery even when the notification is triggered. + pub enabled: bool, + /// Preference record ID (`ntfp_...`). + pub id: String, + #[serde(rename = "type")] + /// Notification type in wire-format. Built-in types use their atom name, e.g. `"app_info"` or `"billing_alert"`. Custom notification types use the form `"custom:"`. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this preference record was last modified (ISO 8601). + pub updated_at: Option>, +} + +/// The complete set of notification preferences belonging to the authenticated viewer. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct NotificationPreferenceList { + /// Array of notification preference objects for the authenticated viewer. Each entry corresponds to a distinct type-and-channel combination. + pub data: Vec, +} + +/// A successful OAuth 2.0 token response. Issued by the token endpoint after a completed authorization or device-flow grant. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct OAuthTokenResponse { + /// Bearer token used to authenticate API requests. Include this value in the `Authorization: Bearer ` header. + pub access_token: String, + /// Number of seconds until the access token expires. + pub expires_in: i64, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Token that can be exchanged for a new access token once the current one expires. `null` if the grant type does not issue refresh tokens. + pub refresh_token: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Space-separated list of scopes granted to the access token. `null` if scope was not included in the grant request. + pub scope: Option, + /// Token type. Always `"Bearer"`. + pub token_type: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The authenticated user associated with this token. `null` when the token is not tied to a specific user (e.g. client-credentials grants). + pub user: Option, +} + +/// A paginated list of reply messages for a thread. The reply array is returned directly, not nested inside a `data` wrapper. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PaginatedReplies { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass as the pagination cursor to retrieve the page of replies that follow this one. `null` when no further pages exist. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass as the pagination cursor to retrieve the page of replies that precede this one. `null` when no earlier pages exist. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether additional reply pages exist beyond the current page. + pub has_more: Option, + /// Array of reply message objects for the current page. + pub replies: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of replies in the thread across all pages. + pub total_count: Option, +} + +/// A documented callable operation exposed by a private service. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PrivateServiceFunction { + /// Human-readable guidance describing when and why to call the operation. + pub description: String, + /// JSON Schema Draft 7 object describing the operation's argument object. + pub input_schema: std::collections::BTreeMap, + /// Stable operation name used when invoking the private service. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional JSON Schema Draft 7 object describing the successful result. + pub output_schema: Option>, +} + +/// An immutable private service with complete callable operation contracts. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PrivateService { + /// Sorted callable definitions exposed by this private service. + pub functions: Vec, + /// Private service ID (`pvs_...`). + pub id: String, +} + +/// A private service's durable connector identity. Read responses never contain +/// an enrollment token or certificate. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PrivateServiceEnrollment { + /// Latest committed connector certificate generation, or zero before enrollment. + pub generation: i64, + /// Canonical certificate-bound service identity. + pub id: String, + /// Immutable private service ID (`pvs_...`). + pub private_service: String, +} + +/// A secret-free page of private service enrollments. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PrivateServiceEnrollmentPage { + /// API field. + pub data: Vec, + /// API field. + pub has_next: bool, + /// API field. + pub has_prev: bool, + /// API field. + pub page: i64, + /// API field. + pub page_size: i64, + /// API field. + pub total_entries: i64, + /// API field. + pub total_pages: i64, +} + +/// A page of private services. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PrivateServicePage { + /// API field. + pub data: Vec, + /// API field. + pub has_next: bool, + /// API field. + pub has_prev: bool, + /// API field. + pub page: i64, + /// API field. + pub page_size: i64, + /// API field. + pub total_entries: i64, + /// API field. + pub total_pages: i64, +} + +/// A named preset that defines the execution model and constraints for a routine. Presets are shared definitions; individual routines reference a preset by name. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct RoutinePreset { + /// Event types that routines using this preset may be triggered by. `["*"]` means the preset accepts any event type. Routines assigned to this preset will be rejected at creation time if their trigger event is not in this list. + pub applicable_events: Vec, + /// Whether routines using this preset can be composed as a step inside a chain routine. Presets with sessionable or asynchronous execution models are not chainable. + pub chainable: bool, + /// Human-readable description of what the preset does and when to use it. + pub description: String, + /// Human-readable display name for the preset, suitable for use in UIs. + pub label: String, + /// Stable machine identifier for the preset, e.g. `"do_task"`. Used when assigning a preset to a routine. + pub name: String, + /// Whether the preset runs inside the thread conversation-session lifecycle. This is distinct from preset_config.session_mode, which controls durable session reuse for do_task and send_message. + pub sessionable: bool, + /// Whether at most one routine with this preset may exist per agent. Attempting to create a second routine with a unique preset on the same agent will be rejected. + pub unique: bool, +} + +/// One ordered, replayable record from a durable workflow journal. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct WorkflowJournalEntry { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Durable command identifier associated with the record, when present. + pub command_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this entry was durably committed. + pub created_at: Option>, + /// Journal entry ID (`wdr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Workflow node associated with the record. `null` for execution-level records. + pub node_id: Option, + /// Replayable workflow record body, including payload, context, environment, metadata, and timestamp. + pub record: std::collections::BTreeMap, + /// Monotonically increasing sequence within the journal. + pub sequence: i64, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Durable timer identifier associated with the record, when present. + pub timer_id: Option, + #[serde(rename = "type")] + /// Workflow record type, such as `node_started`, `node_completed`, or `node_failed`. + pub type_: String, +} + +/// Summary of the durable workflow execution journal associated with a run. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct WorkflowJournal { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When durable workflow execution reached a terminal state. `null` while it is active. + pub completed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the journal was created. + pub created_at: Option>, + /// Highest workflow record sequence durably committed to this journal. + pub current_sequence: i64, + /// Journal execution ID (`wde_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When durable workflow execution started. + pub started_at: Option>, + /// Current durable execution status: `pending`, `running`, `waiting`, `completed`, `failed`, or `cancelled`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the journal was last updated. + pub updated_at: Option>, +} + +/// A forward-paginated journal entry page for an automation or routine run. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct RunJournalPage { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor for the next entry page. `null` when this is the final page. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Always `null`; journal pagination is forward-only. + pub before_cursor: Option, + /// Journal entries ordered by ascending sequence. Empty when the run has no journal. + pub data: Vec, + /// Whether additional entries exist after this page. + pub has_more: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Durable execution summary. `null` when this run has no journal, which is valid for script-backed, preview, or legacy runs. + pub journal: Option, +} + +/// An API key scoped to a developer sandbox, used to authenticate requests against sandbox resources. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SandboxKey { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this key was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this key expires and becomes invalid. `null` if the key does not expire. + pub expires_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The complete secret key value, returned only once when the key is first created. `null` on subsequent retrievals. + pub full_key: Option, + /// Sandbox key ID (`dsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// A short hint showing the last four characters of the key, used for identification. `null` if no hint is available. + pub key_hint: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The full key value for `"publishable"` keys. `null` for `"secret"` keys; use `full_key` instead, which is returned only at creation time. + pub key_value: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this key was last used to authenticate a request. `null` if the key has never been used. + pub last_used_at: Option>, + /// Current lifecycle status of the key. One of `"active"` (usable) or `"revoked"` (permanently disabled). + pub status: String, + #[serde(rename = "type")] + /// The kind of key. One of `"publishable"` (safe for client-side use) or `"secret"` (server-side only). + pub type_: String, +} + +/// An isolated developer sandbox environment used for testing integrations without affecting production data or sending real emails. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Sandbox { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this sandbox was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When an eval sandbox expires and becomes eligible for platform cleanup. `null` for ordinary developer sandboxes. + pub expires_at: Option>, + /// Sandbox ID (`dsb_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API keys associated with this sandbox. `null` if keys were not loaded with this response. + pub keys: Option>, + /// Human-readable display name for the sandbox. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID this sandbox is scoped to, or `null` for an app-level sandbox. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Logo of the owning organization, when present. + pub org_logo: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the owning organization, when org-scoped. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sandbox purpose marker. `"eval"` marks a remote-eval sandbox; `null` for ordinary developer sandboxes. + pub purpose: Option, + /// URL-safe identifier for the sandbox, unique within the application (e.g. `"my-sandbox"`). + pub slug: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this sandbox was last modified (ISO 8601). + pub updated_at: Option>, +} + +/// Contract-defined values for SlackChannelBindingDisclosureState. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum SlackChannelBindingDisclosureState { + /// The pending wire value. + #[serde(rename = "pending")] + Pending, + /// The posted wire value. + #[serde(rename = "posted")] + Posted, + /// The suppressed wire value. + #[serde(rename = "suppressed")] + Suppressed, +} + +/// Contract-defined values for SlackChannelBindingRouteKind. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum SlackChannelBindingRouteKind { + /// The fda wire value. + #[serde(rename = "fda")] + Fda, + /// The resident wire value. + #[serde(rename = "resident")] + Resident, + /// The observer wire value. + #[serde(rename = "observer")] + Observer, + /// The concierge wire value. + #[serde(rename = "concierge")] + Concierge, +} + +/// Contract-defined values for SlackChannelBindingVendorAdminChannelAccess. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum SlackChannelBindingVendorAdminChannelAccess { + /// The invited wire value. + #[serde(rename = "invited")] + Invited, + /// The already_member wire value. + #[serde(rename = "already_member")] + AlreadyMember, + /// The no_slack_user wire value. + #[serde(rename = "no_slack_user")] + NoSlackUser, + /// The failed wire value. + #[serde(rename = "failed")] + Failed, +} + +/// A binding that connects a Slack channel to an ArchAstro team and one or more agents, enabling those agents to receive and respond to messages in that channel. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SlackChannelBinding { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// IDs of every agent attached to this binding, including legacy concierge attachments. Use `resident_agent` and `route_kind` for the effective runtime route. + pub agents: Option>, + /// Whether this channel opts into sustained bot-to-bot conversation, exempting it from the reply loop brake. Defaults to `false`. + pub allow_bot_conversations: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Slack channel ID (e.g. `C01234ABCDE`) that this binding targets. + pub channel: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable label identifying the customer, derived from the binding's embedded config. `null` when not set. + pub customer_label: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Staging thread the deposit pipe copies this channel's mirror content into (`thr_…` public ID). `null` when the pipe is off for this binding. + pub deposit_thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Slack Connect lifecycle: `pending` while the customer has not accepted the invite (nothing mirrors), `posted` once the AI disclosure is in the channel and the channel is live, `suppressed` when relay is stopped. `null` for a binding that never went through Connect provisioning. + pub disclosure_state: Option, + /// Unique identifier for this Slack channel binding. + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the Slack integration that owns this binding. + pub integration: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Cached value of Slack's `is_ext_shared` flag for this channel. May be stale relative to Slack's current state. + pub is_ext_shared_cached: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Cached value of Slack's `is_private` flag for this channel. May be stale relative to Slack's current state. Private channels are member-managed: mutating the binding requires in-channel evidence. + pub is_private_cached: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// IDs of every mirror thread this channel's messages land in (`thr_…` public IDs) that the caller can read, including any legacy peel or chain threads. Empty for a caller with no membership on any of them, and for a channel that has not mirrored anything yet. IDs only: reading a mirror's contents still requires membership on it. + pub mirrors: Option>, + /// Whether the resident agent is currently muted. A muted resident keeps mirroring the channel (reading) but stops replying. A timed mute expires automatically at `muted_until`; this reflects the effective state as of now. Defaults to `false`. + pub muted: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ISO 8601 timestamp when a timed mute expires and replies resume. `null` for an indefinite mute (until an explicit unmute) or when not muted. + pub muted_until: Option, + /// How the resident agent's replies post to Slack: `thread` (default) threads a reply under the message that triggered it; `top_level` posts it flat in the channel. + pub reply_style: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the resident agent selected by Slack ingress. `null` when no resident is attached and the channel is an observer. + pub resident_agent: Option, + /// Effective Slack ingress route. `fda` — a resident on a team-bound channel, replying through the Forward Deployed Agent chain. `resident` — a resident on an internal channel, replying through the channel mirror. `observer` — no resident is attached, so the channel is recorded and nobody replies. `concierge` — no longer returned anywhere; until Track F it was the value for a channel with no resident, meaning the shared concierge agent answered there. The value is retained in this enum so consumers matching on it do not break, and its removal rides a deliberate API change. + pub route_kind: SlackChannelBindingRouteKind, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The customer key this channel's agent is locked to, written when adding the customer finishes. A `posted` binding whose `scope_key` is still null has been accepted but not finished — the addition is either in flight or was refused. + pub scope_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the ArchAstro team this channel is bound to. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether the admin who added this customer ended up inside a Connect channel we created for them: `invited` (we put them in), `already_member` (they were in it already), `no_slack_user` (their account email is not a Slack account in your workspace, so nobody was invited), or `failed` (Slack refused). A created Connect channel is private and has no self-join, so the last two mean the channel has no human from your side until someone already in it adds one. `null` when nobody was added: the channel was adopted rather than created (an existing channel already has its own members), the binding never went through Connect provisioning, or the call had no admin behind it. + pub vendor_admin_channel_access: Option, +} + +/// Paginated list of Slack channel bindings for the requested integration or team. Use the `page` and `per_page` fields to navigate pages of results. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SlackChannelBindingListResponse { + /// Array of Slack channel binding objects for the current page. + pub data: Vec, + /// Current page number (1-indexed). + pub page: i64, + /// Maximum number of bindings returned per page. + pub per_page: i64, + /// Total number of Slack channel bindings matching the query across all pages. + pub total_count: i64, + /// Total number of pages available at the current `per_page` size. + pub total_pages: i64, +} + +/// Contract-defined values for SlackDeliveryOutcomeOperation. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum SlackDeliveryOutcomeOperation { + /// The post wire value. + #[serde(rename = "post")] + Post, + /// The update wire value. + #[serde(rename = "update")] + Update, +} + +/// Contract-defined values for SlackDeliveryOutcomeOutcome. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum SlackDeliveryOutcomeOutcome { + /// The delivered wire value. + #[serde(rename = "delivered")] + Delivered, + /// The floored wire value. + #[serde(rename = "floored")] + Floored, + /// The judge_refused wire value. + #[serde(rename = "judge_refused")] + JudgeRefused, + /// The failed wire value. + #[serde(rename = "failed")] + Failed, +} + +/// What happened to one agent message this platform sent to a Slack channel. Lets you confirm delivery, or find out why a reply never arrived, without reading the channel's mirrored conversation. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SlackDeliveryOutcome { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent whose message this was. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the Slack channel binding in force for this send. `null` when no binding could be resolved, in which case the send was treated as cross-org and floored on that basis. + pub binding: Option, + /// Slack channel ID the send was addressed to. + pub channel: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// For a `failed` send, a short machine-readable cause — `slack:` when Slack rejected the call, or `floor_config` when the content floor could not be evaluated and the send failed closed. + pub failure_reason: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// For a withheld send, the kind of guard that stopped it — `RegexMatch`, `ContainsAny`, `ContainsString`, or `LLMJudge`. `null` when the send was not withheld by a guard. + pub guard_kind: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// For a withheld send, the labels of the guards that stopped it (for example `Contains AWS access key ID`). These are the content policy's own descriptions, recorded as they read at the time of the send; they never contain the withheld message. + pub guard_labels: Option>, + /// Unique identifier for this delivery outcome. + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the platform message this attempt was carrying. Reading that message still requires access to its thread — this field correlates, it does not grant. + pub message: Option, + /// Whether the attempt posted a new Slack message or updated an existing one (replacing a thinking placeholder). + pub operation: SlackDeliveryOutcomeOperation, + /// What happened to the send. `delivered` — Slack accepted the message. `floored` — a deterministic content guard withheld it, so it never left. `judge_refused` — the cross-org judge decided it was not appropriate for this channel's audience. `failed` — Slack rejected the call, or the content floor could not be evaluated and the send failed closed. + pub outcome: SlackDeliveryOutcomeOutcome, + /// When the send was attempted. + pub recorded_at: chrono::DateTime, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Slack thread timestamp the send targeted, letting attempts be grouped into the conversation they belong to. `null` for a top-level channel post. + pub thread_ts: Option, +} + +/// A page of delivery outcomes for one Slack channel, newest first. Page through history with the returned cursors; `since` and `outcome` are filters, not paging controls. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SlackDeliveryOutcomeListResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor for the page of newer outcomes. Pass back as `after_cursor` to poll for attempts recorded since. `null` when the page is empty. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor for the page of older outcomes. Pass back as `before_cursor` to continue into history. `null` when the page is empty. + pub before_cursor: Option, + /// Delivery outcomes matching the query, newest attempt first. + pub data: Vec, + /// True when more outcomes exist beyond this page. + pub has_more: bool, +} + +/// A solution category that organizes solutions in the catalog, identified by a stable key and optionally nested under a parent category. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionCategorySummary { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this category was first created (ISO 8601). `null` for system-built-in categories. + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short prose description of what solutions in this category do. `null` when not configured. + pub description: Option, + /// Solution category config ID (`cfg_...`). + pub id: String, + /// Stable, human-readable key for this category, referenced by solutions via `category_keys`. + pub key: String, + /// Resource type identifier. Always `"SolutionCategory"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lookup key of the underlying config record. `null` when not set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to this category by the publisher. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name shown to users. `null` when not configured. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) that owns this category. `null` for system-scoped categories. + pub org: Option, + /// Scopes under which this category is visible. Possible values are `"system"` (available to all apps) and `"org"` (scoped to the viewer's organization). + pub owners: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key of the parent `SolutionCategory`, enabling a hierarchy. `null` for top-level categories. + pub parent_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Numeric hint for ordering categories in a list. Lower values sort first. `null` when not configured. + pub sort_order: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this category was last modified (ISO 8601). `null` for system-built-in categories. + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Virtual path of the underlying config record. `null` when not set. + pub virtual_path: Option, +} + +/// Paginated list of solution category summaries. Use `page` and `page_size` to navigate pages of results. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionCategoryListResponse { + /// Array of solution category summary objects for the current page. + pub data: Vec, + /// `true` when a subsequent page of results exists. + pub has_next: bool, + /// `true` when a previous page of results exists. + pub has_prev: bool, + /// Current page number (1-indexed). + pub page: i64, + /// Maximum number of entries returned per page. + pub page_size: i64, + /// Total number of distinct solution categories across all pages. + pub total_entries: i64, + /// Total number of pages available at the current `page_size`. + pub total_pages: i64, +} + +/// A brief representation of an agent that references at least one config bundled by a Solution, included in the dependents preview response. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionDependentAgent { + /// Agent ID (`agi_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name of the agent. `null` when no name has been set. + pub name: Option, +} + +/// A preview of the agents and configs that would be affected by deleting a Solution, returned before any deletion occurs so the caller can display a confirmation warning. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionDependentsResponse { + /// Total number of distinct agents that reference at least one config bundled by this Solution. Use this count in the confirmation message; `dependent_agents` may be a shorter sample. + pub dependent_agent_count: i64, + /// A representative sample of the dependent agents, suitable for displaying in a warning list. May contain fewer entries than `dependent_agent_count` when there are many dependents. + pub dependent_agents: Vec, + /// Number of bundled configs that would be detached and preserved rather than deleted, because at least one live agent still references them. + pub preserved_config_count: i64, +} + +/// A reference from another config to an orphaned entry in a solution upgrade diff, explaining why the orphan cannot be safely removed. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionDiffReference { + /// ID of the referencing config (`cfg_...`). + pub id: String, + /// Object type of the referencing config, e.g. `"Automation"` or `"Template"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable stable identifier of the referencing config. `null` if not assigned. + pub lookup_key: Option, + /// Explanation of how the referencing config depends on the orphaned entry. + pub reason: String, +} + +/// A single config entry in a solution upgrade diff, describing what action will be taken on a specific config key. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionDiffEntry { + /// Planned action for this entry. One of `"add"` (new config), `"update"` (existing config changes), `"noop"` (no change needed), `"orphan"` (config no longer in the solution), or `"delete"` (config to be removed). + pub action: String, + /// `true` if the config content differs between the existing and incoming solution versions. + pub content_changed: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config ID (`cfg_...`) if this entry corresponds to an existing config record. `null` for new additions. + pub id: Option, + /// Stable string key identifying this config entry within the solution. + pub key: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config object type, e.g. `"Automation"` or `"Template"`. `null` if not yet known. + pub kind: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable stable identifier for this config. `null` if not assigned. + pub lookup_key: Option, + /// `true` if the MIME type of the config changed between versions. + pub mime_type_changed: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// List of other configs that reference this entry. Populated for orphaned configs that cannot be safely removed. Empty array when there are no references. + pub referenced_by: Option>, + /// `true` if the relative path of the config within the solution changed between versions. + pub relative_path_changed: bool, + /// Role of this config within the solution. Indicates whether it is a primary config or a dependency. + pub role: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Hierarchical path of this config in the config tree. `null` if not assigned. + pub virtual_path: Option, +} + +/// Aggregate counts of each action type across all entries in a solution upgrade diff. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionDiffSummary { + /// Number of config entries that will be newly created by this upgrade. + pub adds: i64, + /// Number of config entries that will be deleted as part of the upgrade. + pub deletes: i64, + /// Number of config entries that are already up to date and require no changes. + pub noops: i64, + /// Number of config entries present in the existing solution that are absent from the incoming version and have no external references blocking removal. + pub orphans: i64, + /// Number of orphaned config entries that cannot be removed because other configs still reference them. + pub referenced_orphans: i64, + /// Number of config entries that exist and will be updated with new content. + pub updates: i64, +} + +/// A non-fatal finding surfaced by a Solution import. The import proceeds despite warnings; validation callers (dry-run) can choose to treat them as failures. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionImportWarning { + /// Machine-readable warning code. `"setup_requirements_dropped"`: a template or config body declares catalog-DSL `setup_requirements` that direct import does not convert — installs read only `setup_actions`, so those setup steps would never surface. + pub code: String, + /// Human-readable explanation of the warning and how to resolve it. + pub message: String, + /// Which bundle entry the warning is about, as `[] ()`. + pub path: String, +} + +/// The machine-readable outcome of a Solution import attempt, indicating whether the import succeeded or requires an upgrade flow to resolve a version conflict. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionImportResult { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Machine-readable conflict code present when `status` is `"conflict"`, identifying the specific conflict reason. `null` when `status` is `"ready"`. + pub code: Option, + /// Whether this result was produced by a dry-run check. `true` when the import was validated without persisting any changes. + pub dry_run: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Semver string of the Solution version already present in the library. `null` when no prior version exists. + pub existing_solution_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Semver string of the Solution version in the bundle being imported. `null` when the bundle does not declare a version. + pub incoming_solution_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of the import status or conflict reason, suitable for display in a confirmation dialog. `null` when no detail is available. + pub message: Option, + /// Outcome of the import check. `"ready"` means the import can proceed as a normal create or update. `"conflict"` means a version conflict was detected and the upgrade flow must be used instead. + pub status: String, + /// Whether the caller must invoke the dedicated upgrade flow to complete the import. Mirrors `status == "conflict"` as a convenience boolean. + pub upgrade_required: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Non-fatal findings the import proceeded despite (present on real imports and dry-runs alike; defaults to an empty array). Dry-run validation callers should surface these — or treat them as failures — before applying the real import. + pub warnings: Option>, +} + +/// The result of importing a Solution bundle into the library, including the Solution config record, a structured import result, and the list of all configs persisted during the transaction. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionImportResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config record was first created (ISO 8601). + pub created_at: Option>, + /// Solution config ID (`cfg_...`). + pub id: String, + /// Structured outcome of the import, including status, conflict details, and version information. + pub import_result: SolutionImportResult, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Deprecated legacy field. One entry per persisted config in the import (including the Solution itself), defaulting to an empty array. Callers should prefer `solution` plus follow-up APIs instead. `key` echoes the caller-supplied input identifier (original lookup_key for top-level configs; `:` for skill / solution-file children). Order is stable: sorted by `key`. + pub installed_configs: Option>, + /// Resource type. Always `"Solution"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The `lookup_key` stored on the Solution config after the import's suffix normalization. `null` when the Solution was not given a lookup key. + pub lookup_key: Option, + /// Full summary of the imported Solution, in the same shape as the individual Solution retrieval endpoint. + pub solution: SolutionSummary, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config record was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The `virtual_path` stored on the Solution config, used as the stable dedupe key across owner scopes. `null` when no virtual path was assigned. + pub virtual_path: Option, +} + +/// One-time connection details for a webhook-auth Automation install. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionInstallResponseWebhook { + /// API field. + pub signing_secret: String, + /// API field. + pub url: String, +} + +/// The runtime resource provisioned by installing a Solution, along with a reference back to the source Solution config. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionInstallResponse { + /// Public ID of the provisioned resource. The prefix reflects the resource kind: `agi_...` for Agent, `aut_...` for Automation, `art_...` for AgentRoutine, `att_...` for AgentTool, `ask_...` for AgentSkill, `cmp_...` for AgentComputer. + pub id: String, + /// Type of the provisioned resource. One of `"Agent"`, `"Automation"`, `"AgentRoutine"`, `"AgentTool"`, `"AgentSkill"`, or `"AgentComputer"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The `lookup_key` stamped on the provisioned resource. `null` for `AgentSkill`, which is a join record and does not carry a lookup key. + pub lookup_key: Option, + /// Solution config ID (`cfg_...`) that was used as the source for this install. + pub solution: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// One-time connection details for a webhook-auth Automation install. + pub webhook: Option, +} + +/// Contract-defined values for SolutionInstanceStatus. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum SolutionInstanceStatus { + /// The active wire value. + #[serde(rename = "active")] + Active, + /// The archived wire value. + #[serde(rename = "archived")] + Archived, +} + +/// A customer-keyed instance stamped from an installed solution template. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionInstance { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Materialized agent for this customer (`agi_...`). `null` for a row without an agent. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name of the materialized agent. `null` when no agent is visible. + pub agent_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque tagged reference to the deployment target. Consumers interpret its kind. + pub attachment_ref: Option>, + /// When this instance was stamped. + pub created_at: chrono::DateTime, + /// Stable vendor-defined key for the customer. + pub customer_key: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable customer label. `null` when the vendor did not provide one. + pub customer_label: Option, + /// Solution instance ID (`sli_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Count of local agent edits relative to the pinned template. `null` when unavailable. + pub local_edit_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Pinned template version record (`cfv_...`). `null` when no version is pinned. + pub pinned_template_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable version number of the pinned template. `null` when unavailable. + pub pinned_version_number: Option, + /// Installed solution template config that stamped this instance (`cfg_...`). + pub solution_template_config: String, + /// Lifecycle status of this stamped instance. + pub status: SolutionInstanceStatus, + /// When this instance was last updated. + pub updated_at: chrono::DateTime, +} + +/// A forward cursor-paginated page of customer solution instances. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionInstanceListResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor for the next page. `null` when this is the final page. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Always `null`; this endpoint supports forward pagination only. + pub before_cursor: Option, + /// Customer solution instances in stable customer-key order. + pub data: Vec, + /// Whether another page exists after this one. + pub has_more: bool, +} + +/// A paginated collection of Solution summaries, with page metadata for navigating the result set. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionListResponse { + /// Array of Solution summary objects for the current page, in the order returned by the query. + pub data: Vec, + /// `true` when a subsequent page exists; `false` when this is the last page. + pub has_next: bool, + /// `true` when a preceding page exists; `false` when this is the first page. + pub has_prev: bool, + /// 1-based index of the current page. + pub page: i64, + /// Maximum number of results included per page. + pub page_size: i64, + /// Total number of Solutions matching the query after deduplication by `solution_id` across owner scopes. + pub total_entries: i64, + /// Total number of pages available at the current `page_size`. + pub total_pages: i64, +} + +/// A single solution tag definition, representing a named classification label that can be applied to solutions. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionTagSummary { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the solution tag was first created (ISO 8601). `null` if unavailable. + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short prose explanation of what the tag represents. `null` if not provided. + pub description: Option, + /// Solution tag config ID (`cfg_...`). + pub id: String, + /// Stable string key for this tag, referenced by `Solution.tag_keys` to associate solutions with this tag. + pub key: String, + /// Object type discriminator. Always `"SolutionTag"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable stable identifier for this tag config, used for lookups and imports. `null` if not assigned. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to this tag. Empty object `{}` when no metadata is present. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name for the tag. `null` if not yet set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization that owns this tag (`org_...`). `null` for system-scoped tags. + pub org: Option, + /// Scopes under which this tag is visible to the caller. One or both of `"system"` (platform-level tag available to all orgs) and `"org"` (tag scoped to the viewer's org). + pub owners: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional integer hint for ordering tags in UI lists. Lower values sort first. `null` if not set. + pub sort_order: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the solution tag was last modified (ISO 8601). `null` if unavailable. + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Hierarchical path used to organize this tag in the config tree. `null` if not assigned. + pub virtual_path: Option, +} + +/// Paginated list of solution tag summaries returned by the list solution tags endpoint. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionTagListResponse { + /// Array of solution tag objects for the current page. + pub data: Vec, + /// `true` if a subsequent page exists; `false` when this is the last page. + pub has_next: bool, + /// `true` if a preceding page exists; `false` when this is the first page. + pub has_prev: bool, + /// Current page number (1-indexed). + pub page: i64, + /// Maximum number of results returned per page. + pub page_size: i64, + /// Total number of distinct solution tags across all pages, after deduplication by key. + pub total_entries: i64, + /// Total number of pages available at the current `page_size`. + pub total_pages: i64, +} + +/// The outcome of a solution upgrade operation, including the computed diff and conflict status. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionUpgradeResult { + /// Ordered list of individual config change entries representing every add, update, noop, orphan, and delete in the diff. + pub changes: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Machine-readable conflict code when `status` is `"conflict"`, e.g. `"review_required"`. `null` when there is no conflict. + pub code: Option, + /// `true` when the upgrade was computed without writing any changes; `false` when changes were committed. + pub dry_run: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Version string of the currently installed solution, as declared in its manifest. `null` if no prior version is installed. + pub existing_solution_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Version string of the incoming solution to be installed, as declared in its manifest. `null` if the incoming manifest omits a version. + pub incoming_solution_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of the conflict or error. `null` when there is no conflict. + pub message: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque fingerprint that uniquely identifies this diff. Pass this value as `review_fingerprint` on a subsequent non-dry-run upgrade call to confirm you have reviewed the diff. `null` if not applicable. + pub review_fingerprint: Option, + /// Overall result of the upgrade. `"ready"` means the upgrade can proceed; `"conflict"` means a blocking issue was detected and the upgrade was not applied. + pub status: String, + /// Aggregate counts of each action type across all diff entries. + pub summary: SolutionDiffSummary, + /// Describes the nature of the version transition. One of `"upgrade"`, `"downgrade"`, `"same"`, or `"unknown"`. + pub version_change: String, +} + +/// Response returned by the solution upgrade endpoint, containing the solution record, the full upgrade diff, and the resulting installed configs. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SolutionUpgradeResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the solution config record was first created (ISO 8601). `null` if unavailable. + pub created_at: Option>, + /// Config ID of the solution record (`cfg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// List of config entries that were installed or updated as part of this upgrade. Empty when `dry_run` is `true` or when no configs changed. + pub installed_configs: Option>, + /// Object type discriminator. Always `"Solution"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable stable identifier for this solution config. `null` if not assigned. + pub lookup_key: Option, + /// Summary of the solution being upgraded, including its name, manifest metadata, and tag keys. + pub solution: SolutionSummary, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the solution config record was last modified (ISO 8601). `null` if unavailable. + pub updated_at: Option>, + /// Detailed result of the upgrade operation, including the computed diff and any conflict information. + pub upgrade_result: SolutionUpgradeResult, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Hierarchical path of the solution in the config tree. `null` if not assigned. + pub virtual_path: Option, +} + +/// Health check response confirming the API is reachable and indicating whether the caller's token is valid. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct StatusPing { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Deployment metadata. + pub deployment: Option, + /// `true` when the platform is reachable and the request was processed successfully. + pub success: bool, + /// Details about the authentication token used in this request. + pub token: std::collections::BTreeMap, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The authenticated user associated with the token. `null` when the token is invalid or absent. + pub user: Option, +} + +/// A long-lived API credential associated with a system account, used to authenticate server-to-server requests. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SystemAccessToken { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this token was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the token expires. `null` on legacy rows that predate stored expiry. + pub expires_at: Option>, + /// Token ID (`sat_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this token was last used to authenticate a request. `null` if the token has never been used. + pub last_used_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable label assigned to this token at creation time. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this token was revoked. `null` if the token is still active. + pub revoked_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Space-separated OAuth scopes stamped on the token. `null` on legacy rows; treat as `full_access`. + pub scopes: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Raw bearer token string. Present only in the response to the create request; never returned again after that. + pub token: Option, +} + +/// Viewer-safe details about a task's current coding-session lease. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct TaskSessionLeaseSummary { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the coding session. + pub harness: String, + /// Display name supplied by the coding session that holds the lease. + pub session_name: String, +} + +/// A task representing a unit of work, optionally assignable to a user or agent. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Task { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind. + pub blocked_by_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open. + pub closed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of comments posted on this task. + pub comments_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted). + pub created_by_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted. + pub created_by_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted. + pub created_by_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included. + pub current_lease: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Long-form description or notes for the task. `null` if no description has been provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). `null` if no due date is set. + pub due_date: Option>, + /// Task ID (`tsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read. + pub is_blocked: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set. + pub metadata: Option>, + /// Human-readable title of the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted). + pub owner_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment. + pub sandbox: Option, + /// Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks. + pub subtasks_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team. + pub user: Option, +} + +/// A comment posted on a task by a user or an agent, including resolved author information. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct TaskComment { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved author details including `id`, `name`, `alias`, and `profile_picture`. `null` if no author is set or the author cannot be resolved (e.g. authoring agent was deleted). + pub author_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that posted this comment (`agi_...`). `null` if the author is a human user, or if the authoring agent was later deleted. + pub author_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who posted this comment (`usr_...`). `null` if the author is an agent, or if author provenance was cleared after the authoring agent was deleted. + pub author_user: Option, + /// Plain-text body of the comment. + pub body: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this comment was posted (ISO 8601). + pub created_at: Option>, + /// Comment ID (`tcmt_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization that owns this comment (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sandbox ID this comment is scoped to. `null` for comments outside a sandbox environment. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the task this comment belongs to (`tsk_...`). + pub task: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team the task belongs to (`tem_...`). `null` if not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this comment was last edited (ISO 8601). + pub updated_at: Option>, +} + +/// A task-session lease returned only to its matching holder. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct TaskSessionLease { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the matching coding session. + pub harness: String, + /// Caller-generated fencing token required for renewal and release. + pub lease_id: String, + /// Server timestamp for the most recent claim, reclaim, or renewal. + pub renewed_at: chrono::DateTime, + /// Opaque caller-generated coding-session identifier. + pub session_id: String, + /// Display name supplied by the matching coding session. + pub session_name: String, +} + +/// A team invite containing a short alphanumeric code that other users can present to join the team. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct TeamInvite { + /// Short alphanumeric join code. Pass this value as `join_code` to the join-with-code endpoint to add a user to the team. + pub code: String, +} + +/// A record representing a user's or agent's membership in a team, including their resolved identity details and role. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct TeamMembership { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The agent associated with this membership, as an expanded agent object. `null` when the member is a user, the type is unknown, or the association is not preloaded. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this membership record was created (ISO 8601). + pub created_at: Option>, + /// Team membership ID (`tmb_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the principal joined the team (ISO 8601). + pub joined_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to this membership record. `null` if no metadata has been set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the member, derived from the associated user or agent. `null` if the principal is unknown. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture of the member, derived from the associated user or agent. `null` if not set or principal is unknown. + pub profile_picture: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The member's role within the team. One of `"owner"`, `"admin"`, or `"member"`. + pub role: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The team this membership belongs to, as an expanded team object. `null` when the team association is not preloaded. + pub team: Option>, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved principal type. One of `"user"`, `"agent"`, or `"unknown"` when the principal cannot be determined. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this membership record was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The user associated with this membership, as an expanded user object. `null` when the member is an agent, the type is unknown, or the association is not preloaded. + pub user: Option, +} + +/// A paginated list of team memberships returned by the list team memberships endpoint. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct TeamMembershipListResponse { + /// Array of team membership objects for the current page. + pub data: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` if a subsequent page exists; `false` when this is the last page. + pub has_next: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` if a previous page exists; `false` when this is the first page. + pub has_prev: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current page number, starting at `1`. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of results returned per page. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of team memberships matching the applied filters across all pages. + pub total_entries: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of pages given the current `page_size`. + pub total_pages: Option, +} + +/// Contract-defined values for ThreadMessageAgentMode. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ThreadMessageAgentMode { + /// The cli wire value. + #[serde(rename = "cli")] + Cli, + /// The embedded wire value. + #[serde(rename = "embedded")] + Embedded, +} + +/// Contract-defined values for ThreadMessageVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ThreadMessageVisibility { + /// The default wire value. + #[serde(rename = "default")] + Default, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// A single message posted to a thread, as seen from the developer portal. Includes sender information, optional attachments, and scoping identifiers. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ThreadMessage { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for private messages. Only returned to resource owners (and privileged/org-admin viewers); `null` otherwise. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Admin-only diagnostic metadata for the message, including execution trajectory details. Only present in developer portal responses. + pub admin: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) associated with the message. `null` if not agent-scoped. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path. + pub agent_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// App ID (`app_...`) that the message belongs to. + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Files or media attached to the message. Empty array if no attachments are present. + pub attachments: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Text content of the message. `null` if the message contains only attachments. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the message was posted to the thread (ISO 8601). + pub created_at: Option>, + /// Message ID (`msg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value metadata attached to the message. Always present; defaults to an empty object. The `metadata` query parameter filters on this same object, so a caller can read back the field it selects on. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) this message is scoped to. `null` if not org-scoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages. + pub root_message_id: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sandbox ID (`dsb_...`) this message is scoped to. `null` if not sandbox-scoped. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Public ID of the sender (e.g. `usr_...` or `agt_...`). `null` for system-generated messages. + pub sender: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the message sender. `null` if unavailable. + pub sender_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Category of entity that sent the message. One of `"user"`, `"agent"`, or `"system"`. + pub sender_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`tea_...`) associated with the message. `null` if not team-scoped. + pub team: Option, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) associated with the message. `null` if not user-scoped. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message-level visibility. `default` follows thread membership; `private` is limited to the sender and ACL `read` grantees. + pub visibility: Option, +} + +/// The read status of a thread for a specific user, indicating how far they have read and how many messages remain unread. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ThreadReadStatus { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message ID (`msg_...`) of the last message the user has read in this thread. `null` if the user has never read any message in the thread. + pub last_read_message: Option, + /// Thread ID (`thr_...`) that this read status belongs to. + pub thread: String, + /// Number of messages in the thread that the user has not yet read. + pub unread_count: i64, +} + +/// A recorded sequence of AI messages and tool interactions representing a single AI reasoning session. Trajectories are stored as structured message logs and can be replayed or inspected after execution. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Trajectory { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the trajectory was recorded (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the storage file that persists the raw trajectory data (`fil_...`). `null` if the trajectory has not been written to a file. + pub file: Option, + /// Trajectory ID (`trj_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Serialized message log for this trajectory. Contains the ordered sequence of AI and tool messages produced during the session. + pub messages: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this trajectory belongs to (`org_...`). `null` for trajectories outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this trajectory is scoped to (`sbx_...`). `null` for production trajectories. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team this trajectory is scoped to (`team_...`). `null` for trajectories not associated with a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the trajectory record was last updated (ISO 8601). + pub updated_at: Option>, +} + +/// A shareable invite created by a user, optionally scoped to a thread. Recipients can use the invite key to join or start a conversation. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct UserInvite { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this invite was created (ISO 8601). + pub created_at: Option>, + /// Invite ID (`uin_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Secret bearer token used to accept this invite. Treat this value like a password — do not log or expose it publicly. + pub key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the invite at creation time. Defaults to an empty object. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this invite is scoped to (`thr_...`). `null` if the invite is not bound to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The user who created this invite. + pub user: Option, +} + +/// The result of a configuration validation check, indicating whether the config is valid and listing any errors or warnings. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ValidationResult { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// List of human-readable error messages describing why validation failed. Empty or absent when `valid` is `true`. + pub errors: Option>, + /// `true` if the configuration passed all validation checks, `false` if one or more errors were found. + pub valid: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// List of human-readable warning messages emitted during validation. Warnings do not cause `valid` to be `false` but indicate potentially problematic configuration. + pub warnings: Option>, +} + +/// Externally executable work yielded by a durable workflow. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct WorkflowWorkItem { + /// Agent assigned to execute this work. + pub agent: String, + /// Number of times this work has been freshly claimed or reclaimed. + pub attempt_count: i64, + /// Opaque journal command identity used to resume the workflow exactly once. + pub command_id: String, + /// API field. + pub created_at: chrono::DateTime, + /// Durable workflow execution that owns this work. + pub execution: String, + /// Work item ID (`wdi_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the current claim expires. Null for queued or terminal work. + pub lease_expires_at: Option>, + /// Workflow graph node that yielded the work. + pub node_id: String, + /// Instructions and participant bindings needed to execute the work. + pub payload: std::collections::BTreeMap, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Routine run that owns the execution, when this work came from a routine. + pub routine_run: Option, + /// Current queue lifecycle status. + pub status: String, + #[serde(rename = "type")] + /// Stable resource discriminator. Always `workflow_work_item`. + pub type_: String, + /// API field. + pub updated_at: chrono::DateTime, +} + +/// A claimed workflow work item and its caller-held lease token. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct WorkflowWorkItemLease { + /// Opaque lease token that must be persisted and presented for later transitions. + pub lease_owner: String, + /// The claimed, resumed, started, or heartbeated work item. + pub work_item: WorkflowWorkItem, +} + +/// Result of polling an agent's durable workflow work queue. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct WorkflowWorkItemClaim { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Claimed or resumed work and its lease; null when no eligible item exists. + pub data: Option, +} + +/// Active durable workflow work available to the viewer. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct WorkflowWorkItemList { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor for the next page, or null at the end. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Always null because queue pagination is forward-only. + pub before_cursor: Option, + /// Active work items. Lease tokens are intentionally never included in list responses. + pub data: Vec, + /// Whether another page of work exists. + pub has_more: bool, +} + +/// A key-value memory record stored for an agent, optionally scoped to a user. Memory entries persist across invocations and may carry an expiration time. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct WorkingMemoryEntry { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this memory entry (`agt_...`). + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this memory entry was first written (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this entry will be automatically deleted. `null` if the entry does not expire. + pub expires_at: Option>, + /// Working memory entry ID (`amm_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The string key used to look up this memory entry within the agent's memory namespace. + pub key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this memory entry was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The string value stored under `key`. May be any serialized content the agent wrote. + pub value: Option, +} + +/// Paginated list of working memory entries stored for an agent. Includes page metadata to support sequential page traversal. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct WorkingMemoryEntryListResponse { + /// Array of working memory entry objects for the current page. + pub data: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` if a subsequent page exists and can be fetched by incrementing the page number. + pub has_next: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` if a previous page exists and can be fetched by decrementing the page number. + pub has_prev: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The current page number, starting at `1`. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of entries returned per page. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of working memory entries matching the query across all pages. + pub total_entries: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of pages given the current `page_size`. + pub total_pages: Option, +} diff --git a/src/generated/v1.rs b/src/generated/v1.rs new file mode 100644 index 0000000..3135adc --- /dev/null +++ b/src/generated/v1.rs @@ -0,0 +1,20435 @@ +// Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License. +// This file is auto-generated by @archastro/sdk-generator. Do not edit. +// Content hash: e3260c953376 + +use crate::generated::types::*; +use crate::sse::{SseDecode, SseStream}; +use crate::{Client, Result}; +use reqwest::Method; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +/// Query parameters for get_api_v1_activity_feed. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ActivityFeedParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// One or more entry kinds to include. Accepted values: routine_run, automation_run, thread_story, agent_quality_verdict, work_item_assigned, work_item_completed, generic. Omit to return all kinds. + pub kind: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// One or more severity levels to include. Accepted values: debug, info, warn, error, audit. Omit to return all levels. + pub level: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to entries associated with these agent IDs (`agt_...`). Accepts multiple values. + pub agent: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to entries associated with these thread IDs (`thr_...`). Accepts multiple values. + pub thread: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to entries associated with these team IDs (`tem_...`). Accepts multiple values. + pub team: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to entries associated with these organization IDs (`org_...`). Accepts multiple values. + pub org: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to entries that share this correlation group identifier. Useful for tracing a chain of related events. + pub correlation_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of entries to return per page. Defaults to 50; maximum is 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor from a previous response's `before_cursor` field. Returns entries older than the cursor's position. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor from a previous response's `after_cursor` field. Returns entries newer than the cursor's position. + pub after_cursor: Option, +} + +/// Contract-defined alternatives for GetApiV1ActivityFeedResponseDataItemAgent. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetApiV1ActivityFeedResponseDataItemAgent { + /// Variant1 union variant. + Variant1(String), + /// Variant2 union variant. + Variant2(Value), +} + +/// Contract-defined alternatives for GetApiV1ActivityFeedResponseDataItemUser. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetApiV1ActivityFeedResponseDataItemUser { + /// Variant1 union variant. + Variant1(String), + /// Variant2 union variant. + Variant2(Value), +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ActivityFeedResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The agent that produced this event. Returns an agent ID (`agi_...`) by default, or an expanded agent object when the association is loaded. `null` if no agent is associated. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the application that produced this entry (`dap_...`). `null` if not scoped to an app. + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of attachment objects associated with this entry. Each attachment has a `type` field (e.g. `"file"`, `"task"`, `"artifact"`) and type-specific additional fields. Empty array when there are no attachments. + pub attachments: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the automation run that produced this entry (`atr_...`). `null` if not produced by an automation run. + pub automation_run: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// A longer explanation of the event rendered as Markdown. `null` if no additional content is available. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// An opaque string used to group related entries together. Entries sharing the same `correlation_id` belong to a single logical operation. `null` if not correlated. + pub correlation_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this activity feed entry was created (ISO 8601). + pub created_at: Option>, + /// Activity feed entry ID (`afe_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The type of event this entry represents, e.g. `"agent_step"` or `"tool_call"`. Determines how `title`, `content`, and `attachments` should be interpreted. + pub kind: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Severity level of the event. One of `"info"`, `"warning"`, or `"error"`. `null` if no severity is set. + pub level: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata stored on this entry. Returns an empty object when no metadata is set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this entry belongs to (`org_...`). `null` if not org-scoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent routine run that produced this entry (`arr_...`). `null` if not produced by a routine run. + pub routine_run: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the sandbox environment this entry was generated in. `null` in production contexts. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent session record this entry belongs to (`ase_...`). `null` if not part of an agent session. + pub session_record: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team this entry is associated with (`tem_...`). `null` if not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this entry is associated with (`thr_...`). `null` if not linked to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// A one-line human-readable summary of the event. `null` if the entry has no title. + pub title: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this activity feed entry was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The user who triggered this event. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if no user is associated. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ActivityFeedResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass as `after_cursor` to retrieve the next newer page. Absent when no newer entries exist. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass as `before_cursor` to retrieve the next older page. Absent when no older entries exist. + pub before_cursor: Option, + /// Array of activity feed entry objects for the current page, ordered newest first. + pub data: Vec, + /// `true` when additional entries exist beyond this page in the requested direction. + pub has_more: bool, +} + +/// Runs a shell command on the specified computer and returns its combined +/// output and exit code. The call blocks until the command completes; there +/// is no streaming or timeout override — plan accordingly for long-running +/// commands. +/// +/// Requires an app-scoped API key. The computer must be in the `running` +/// state. Commands run as the default unprivileged user on the computer. +/// A non-zero `exit_code` in the response does not produce an HTTP error; +/// inspect `exit_code` and `output` to determine success. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentComputersComputerExecInput { + /// Shell command to execute, e.g. `"ls -la /home"`. + pub command: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute path to use as the working directory when executing the command. Defaults to the computer's home directory when omitted. + pub dir: Option, +} + +/// Updates the `value` or `description` of an existing environment variable. +/// Only fields provided in the request are changed; omitted fields retain their +/// current values. The variable `key` cannot be changed after creation. +/// +/// The updated value is stored securely and, like creation, the plaintext is +/// never returned; the response contains the masked representation. The +/// authenticated user must have access to the agent's parent app. Pass the app +/// scope via the `app` parameter when calling with an API key that is scoped to +/// a specific app. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentEnvVarsEnvVarInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated human-readable note describing what the variable is used for. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New plaintext secret value. The value is encrypted at rest and never returned in full. + pub value: Option, +} + +/// Query parameters for get_api_v1_agent_installations. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentInstallationsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent IDs (`agi_...`) to filter results by. When omitted, installations for all agents in the app are returned. Multiple values are OR'd. + pub agent: Option>, +} + +/// Transitions an installation to the `suspended` state, disabling event processing +/// and signaling that the installation requires administrative attention. Unlike +/// pausing, suspension typically indicates a policy or compliance hold rather than a +/// temporary operational stop. +/// +/// An optional `reason` string can be supplied to record why the installation was +/// suspended; this is stored on the installation and visible when you retrieve it. +/// Only installations that are not already suspended can be suspended — sending this +/// request for an already-suspended installation returns 422. The caller must have +/// app scope for the app that owns the installation. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentInstallationsInstallationSuspendInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable explanation for the suspension. Stored on the installation and visible when you retrieve it. Omit to suspend without recording a reason. + pub reason: Option, +} + +/// Attaches a new source to an existing installation, making its content available +/// to the installation's agent as context. The source type and payload must be valid +/// for the installation's kind; invalid combinations return 422. +/// +/// This endpoint requires an app-scoped token. The installation must belong to an +/// agent accessible by the authenticated caller. Once created, the source begins +/// processing asynchronously — its `state` will transition from `"pending"` as +/// ingestion progresses. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentInstallationsInstallationInstallationSourcesInput { + /// Type-specific payload for the source. The accepted keys depend on the `type` value; invalid or missing payload fields return 422. + pub payload: std::collections::BTreeMap, + #[serde(rename = "type")] + /// Source type slug identifying the kind of content being attached, e.g. `"file/document"` or `"web/link"`. + pub type_: String, +} + +/// Query parameters for get_api_v1_agent_routine_runs. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentRoutineRunsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter by one or more agent IDs (`agi_...`) or `lookup_key` values. Repeat the parameter (e.g. `?agent[]=agi_a&agent[]=agi_b`) to OR multiple agents. Omit to return runs for all agents. + pub agent: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter by run status. One of `"pending"`, `"running"`, `"completed"`, `"failed"`, `"skipped"`, or `"cancelled"`. Omit to return runs in any status. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of runs to return. Defaults to 50; maximum is 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor from a previous response's `before_cursor` field. Returns the page of runs older than that cursor position. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor from a previous response's `after_cursor` field. Returns the page of runs newer than that cursor position. + pub after_cursor: Option, +} + +/// Typed events emitted by get_api_v1_agent_routine_runs__agent_routine_run_stream. +#[derive(Debug, Clone, PartialEq)] +pub enum GetApiV1AgentRoutineRunsAgentRoutineRunStreamEvent { + /// Contract-defined stream event. + RunUpdate(AgentRoutineRun), +} +impl SseDecode for GetApiV1AgentRoutineRunsAgentRoutineRunStreamEvent { + fn decode(event: &str, data: &str) -> Result { + match event { + "run_update" => Ok(Self::RunUpdate(serde_json::from_str(data)?)), + other => Err(crate::Error::UnknownSseEvent(other.to_owned())), + } + } +} + +/// Query parameters for get_api_v1_agent_routines. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentRoutinesParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent IDs (`agi_...`) to filter routines by. Omit to return routines across all agents. Multiple values are OR'd. + pub agent: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Event type string to filter by (e.g. `"agentroutine.invoked"`). Omit to return routines for all event types. + pub event_type: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentRoutinesRoutineInputAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentRoutinesRoutineInputAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentRoutinesRoutineInputAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentRoutinesRoutineInputAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentRoutinesRoutineInputMessagePolicy { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Required and non-empty for private visibility. Sources are additive. Routine owner includes the agent owner and optional user co-owner. + pub recipients: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message visibility. One of `default` or `private`. + pub visibility: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentRoutinesRoutineInputPresetConfigLlm { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Provider-prefixed model identifier for this routine or step, e.g. `"openrouter/anthropic/claude-sonnet-latest"`. When omitted, the agent's default model is used. + pub model: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentRoutinesRoutineInputPresetConfig { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Custom task or behavior instructions for the preset (max 10,000 chars). + pub instructions: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// LLM invocation settings (e.g. a `model` override for this routine/step). + pub llm: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Session mode: `stateless` (default, new session per trigger) or `session` (find-or-create a persistent session scoped by `session_scope`). + pub session_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `session_mode` is `session`, controls session scoping: `per_user` (default), `per_key`, `per_org`, or `global`. + pub session_scope: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// IDs of structured message templates that constrain the agent's responses to predefined structured formats. + pub structured_message_template_ids: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentRoutinesRoutineInputStepsItemPresetConfigLlm { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Provider-prefixed model identifier for this routine or step, e.g. `"openrouter/anthropic/claude-sonnet-latest"`. When omitted, the agent's default model is used. + pub model: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentRoutinesRoutineInputStepsItemPresetConfig { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Custom task or behavior instructions for the preset (max 10,000 chars). + pub instructions: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// LLM invocation settings (e.g. a `model` override for this routine/step). + pub llm: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Session mode: `stateless` (default, new session per trigger) or `session` (find-or-create a persistent session scoped by `session_scope`). + pub session_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `session_mode` is `session`, controls session scoping: `per_user` (default), `per_key`, `per_org`, or `global`. + pub session_scope: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// IDs of structured message templates that constrain the agent's responses to predefined structured formats. + pub structured_message_template_ids: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentRoutinesRoutineInputStepsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of a saved config to use as the handler body. Required when `handler_type` is `"workflow_graph"`; also accepted for `"script"` as an alternative to an inline `script` value. + pub config: Option, + /// Execution handler for this step. One of `"preset"`, `"script"`, or `"workflow_graph"`. + pub handler_type: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional key-value map binding outputs from prior steps to this step's input variables. + pub inputs: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional label for this step. Must be unique within the chain when provided. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Error handling policy for this step. One of `"halt"` (default), `"continue"`, or `"retry"`. + pub on_error: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key under which this step's result is stored and addressable by downstream steps. Defaults to `name` when omitted. + pub output_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Configuration overrides for the preset, using the same shape as the routine-level `preset_config`. You may include an `llm` key to override the agent's default model for this step. `null` if not provided. + pub preset_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Name of the preset to invoke. Required when `handler_type` is `"preset"`. + pub preset_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Inline script source code to execute. Used when `handler_type` is `"script"` and no `config` is provided. + pub script: Option, +} + +/// Updates one or more fields of the specified routine. Only the fields you +/// include are changed; omitted fields retain their current values. To change the +/// execution model, supply a new `handler_type` along with its required handler +/// body field (`config`, `script`, or `preset_name`). +/// +/// When `template` is supplied, the routine's configuration is re-resolved from +/// the template before applying any additional field overrides. The routine's +/// `status`, `lookup_key`, and agent attachment are always preserved regardless +/// of template content. Updating `steps` replaces the entire step list — send +/// the full desired list, not a partial diff. Requires app scope. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentRoutinesRoutineInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated access control list. Replaces the existing ACL entirely. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Workflow config ID (`cfg_...`). Used when `handler_type` is `"workflow_graph"`. + pub config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New human-readable description of what this routine does. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Mapping of event types to trigger configuration. Each key is an event type string; each value is an object with a `"filters"` map and an optional `"dedupe_key_path"` (a JSON path used to deduplicate events, e.g. `"$.thread.id"`). + pub event_config: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Event type that triggers this routine. Deprecated — use `event_config` instead. + pub event_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New execution model. One of `"workflow_graph"`, `"script"`, `"preset"`, or `"chain"`. + pub handler_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New stable, unique key for deterministic lookup. Must be unique within the app. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated visibility and explicit recipient selection for emitted messages. + pub message_policy: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated arbitrary key-value metadata. Replaces the existing metadata entirely. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New human-readable display name for the routine. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated configuration passed to the preset at runtime. + pub preset_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Name of the registered preset to use. Used when `handler_type` is `"preset"`. + pub preset_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New cron expression for time-triggered routines (e.g. `"0 9 * * 1"`). Must not be more frequent than once per hour. + pub schedule: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New inline script source. Used when `handler_type` is `"script"`. + pub script: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated ordered list of steps for a chain handler. Required when `handler_type` is `"chain"`; must be omitted or empty otherwise. Replaces the entire existing step list — send the full desired list, not a partial diff. + pub steps: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// AgentRoutineTemplate config ID (`cfg_...`) or lookup key. When provided, the routine's configuration is re-resolved from the template before applying other param overrides. The routine's `status`, `lookup_key`, and agent attachment are always preserved. + pub template: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated trigger context. One of `"chat_session"` or `"event"`. + pub trigger_context: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional co-owner user ID (`usr_...`) to set on the routine. Must be supplied explicitly — the caller's identity is never auto-stamped. Omit to leave the existing value unchanged; send `null` (or an empty string) to clear the current co-owner. + pub user: Option, +} + +/// Contract-defined values for PostApiV1AgentRoutinesRoutineInvokeInputDeliveryType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum PostApiV1AgentRoutinesRoutineInvokeInputDeliveryType { + /// The none wire value. + #[serde(rename = "none")] + None, + /// The thread wire value. + #[serde(rename = "thread")] + Thread, + /// The reply wire value. + #[serde(rename = "reply")] + Reply, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentRoutinesRoutineInvokeInputDelivery { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message ID (`msg_...`) to reply to. Required when `type` is `reply`. + pub message: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Destination thread ID (`thr_...`). Required when `type` is `thread`. + pub thread: Option, + #[serde(rename = "type")] + /// Delivery mode. Use `none` for no delivery, `thread` to post to a conversation, or `reply` to preserve a message reply anchor. + pub type_: PostApiV1AgentRoutinesRoutineInvokeInputDeliveryType, +} + +/// Triggers an on-demand invocation of the specified routine, dispatching an +/// asynchronous agent run and returning a run record immediately. The routine must +/// be active and must have `event_type` set to `"agentroutine.invoked"`. +/// +/// The routine's `preset_config.session_mode` determines session behavior: each +/// call may create a new session (`"stateless"`) or reuse an existing one +/// (`"session"`). When `session_scope` is `"per_user"`, the `user` param is +/// required for S2S and developer callers; authenticated client callers always +/// use their own identity. When `session_scope` is `"per_key"`, `session_key` +/// is required. +/// +/// Supply `idempotency_key` to safely retry invocations — if a completed run +/// already exists for that key a 409 Conflict is returned rather than creating +/// a duplicate run. Entitlement for LLM calls is checked at request time; +/// customers on plans that do not include this feature receive 402. +/// +/// Use `delivery` to propagate the final textual result into a conversation. +/// `{"type":"reply","message":"msg_..."}` preserves the message's external +/// origin (for example Slack), while `{"type":"thread","thread":"thr_..."}` +/// posts without a reply anchor. Chain routines deliver only their final result. +/// +/// For workflow-graph routines that dispatch distributed work, pass optional +/// `participants` (map of symbolic refs to agent ids, e.g. +/// `{"investigator":"agi_..."}`) as a **top-level** field next to free-form +/// invoke inputs — same shape as automation invoke. Free-form fields stay on +/// `event_payload`; participants are stored in the run's top-level +/// `participants` field and exposed through workflow system context so +/// `embed_agent` nodes can resolve assignees. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentRoutinesRoutineInvokeInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Typed final-result delivery: reply to a `message`, post to a `thread`, or `none` (the default). + pub delivery: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Unique key used to deduplicate invocations. Resubmitting the same key returns 409 if a completed run already exists. + pub idempotency_key: Option, + /// The user message to send to the agent for this invocation. + pub message: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to this invocation. Not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Map of symbolic participant refs to agent ids (`agi_...` or UUID) for distributed embed_agent handoffs. Stored in the run's top-level `participants` field. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key used to identify and resume a session when `session_scope` is `"per_key"`. Required in that mode. + pub session_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Thread ID (`thr_...`) to post the preset output into. Omit to skip thread posting. + pub thread_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID to associate with the session. For S2S and developer callers only; authenticated client callers always use their own identity. + pub user: Option, +} + +/// Query parameters for get_api_v1_agent_routines__routine_runs. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentRoutinesRoutineRunsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter runs by status. One of `"pending"`, `"running"`, `"completed"`, `"failed"`, or `"skipped"`. Omit to return runs in all statuses. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of runs to return per page. Defaults to 50; maximum is 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor from a previous response's `before_cursor` field. Returns the page of runs older than this cursor. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor from a previous response's `after_cursor` field. Returns the page of runs newer than this cursor. + pub after_cursor: Option, +} + +/// Query parameters for get_api_v1_agent_routines_runs__run_journal. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentRoutinesRunsRunJournalParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of entries to return. Defaults to 50; maximum is 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor from the previous response's `after_cursor` field. + pub after_cursor: Option, +} + +/// Query parameters for get_api_v1_agent_sessions. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentSessionsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter by agent IDs (`agi_...`). Omit to return sessions for all agents in the app. Multiple values are OR'd. + pub agent: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter by one or more session statuses. Accepted values are `"pending"`, `"running"`, `"waiting"`, `"completed"`, `"failed"`, and `"cancelled"`. Omit to return sessions in any status. + pub status: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter to sessions that were created by the specified routine run IDs. Accepts up to 100 IDs. Omit to return sessions regardless of their originating routine run. + pub routine_run: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, omits sessions that were created automatically by the platform rather than by your app. Defaults to `false`. + pub exclude_system: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of sessions to return. Defaults to 25; maximum is 100. + pub limit: Option, +} + +/// Creates a new agent session and enqueues it for execution. The session begins +/// in `"pending"` status and transitions to `"running"` once the platform picks +/// it up. Subscribe to the session stream endpoint to receive real-time status +/// updates. +/// +/// You must supply the ID of an agent that the authenticated app owns and a +/// plain-text `instructions` string describing the task. All other parameters +/// are optional and default to the agent's configured limits when omitted. +/// +/// Set `start_idle` to `true` to create the session without running an opening +/// turn — it begins in `"waiting"` status and runs its first turn only once you +/// post a message (see the message endpoint). Use this when you want the first +/// message to drive the session instead of the `instructions` alone. +/// +/// Requires an app-scoped API key. Returns HTTP 201 on success. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentSessionsInput { + /// Agent ID (`agi_...`) of the agent that will execute the session. + pub agent: String, + /// Plain-text task description given to the agent as its primary objective for this session. + pub instructions: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of tool invocations allowed within a single agent turn. Defaults to 25. + pub max_runs_per_turn: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of tokens the agent may consume across all turns. Defaults to 20,000. + pub max_tokens: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of agent turns before the session is automatically terminated. Defaults to 100. + pub max_turns: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to attach to the session. Stored and returned as-is; not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name for the session. Useful for identifying sessions in the dashboard. `null` if omitted. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, create the session without running an opening turn. The session starts in `"waiting"` status and runs its first turn only when you post a message. Defaults to `false`, which runs an initial turn from `instructions` immediately. + pub start_idle: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`tea_...`) to associate with this session for access-control and attribution purposes. `null` if omitted. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Thread ID (`thr_...`) to link this session to an existing conversation thread. `null` if omitted. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID to associate with this session for attribution purposes. `null` if omitted. + pub user: Option, +} + +/// Updates the mutable fields of an agent session. Currently only `metadata` +/// can be changed; supply any key-value pairs you want to store alongside the +/// session. Omitting `metadata` leaves it unchanged. +/// +/// This endpoint may be called while the session is in any status, including +/// while it is actively running. +/// +/// Requires an app-scoped API key. The session must belong to an agent owned +/// by the authenticated app. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentSessionsAgentSessionInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to attach to the session. Replaces the existing metadata map entirely. Omit to leave the current metadata unchanged. + pub metadata: Option>, +} + +/// Appends a message to the inbox of the specified agent session. The agent +/// reads inbox messages at the start of each turn; sending a message to a +/// `"waiting"` session signals it to resume execution. +/// +/// Use `role` to identify the sender type. The default role is `"user"`. +/// Arbitrary key-value metadata may be attached to the message for tracking +/// or display purposes. +/// +/// Requires an app-scoped API key. The session must belong to an agent owned +/// by the authenticated app. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentSessionsAgentSessionMessageInput { + /// Plain-text body of the message to deliver to the agent. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to attach to the message. Stored and returned as-is; not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Role of the message sender. Typically `"user"` or `"tool"`. Defaults to `"user"`. + pub role: Option, +} + +/// Typed events emitted by get_api_v1_agent_sessions__agent_session_stream. +#[derive(Debug, Clone, PartialEq)] +pub enum GetApiV1AgentSessionsAgentSessionStreamEvent { + /// Contract-defined stream event. + SessionUpdate(AgentSession), +} +impl SseDecode for GetApiV1AgentSessionsAgentSessionStreamEvent { + fn decode(event: &str, data: &str) -> Result { + match event { + "session_update" => Ok(Self::SessionUpdate(serde_json::from_str(data)?)), + other => Err(crate::Error::UnknownSseEvent(other.to_owned())), + } + } +} + +/// Query parameters for get_api_v1_agent_skills. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentSkillsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to skills belonging to the specified agent(s). Accepts one or more agent IDs (`agt_...`) or lookup keys. Omit to return skills across all agents in the app. + pub agent: Option>, +} + +/// Attaches a skill config to an agent, creating an agent skill record and +/// returning it with an initial status of `"inactive"`. Use the activate +/// endpoint to make the skill available during agent runs. +/// +/// Requires an app-scoped API key. The `agent` and `config` must both belong +/// to the authenticated app. Supplying a `config` that does not exist within +/// the app returns 422. Returns 201 on success. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentSkillsInput { + /// Agent ID (`agt_...`) to attach the skill to. + pub agent: String, + /// Skill config ID (`cfg_...`) that defines the skill's behavior. Must belong to the authenticated app. + pub config: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional plain-text instruction override. When supplied, replaces the default instruction from the skill config for this agent. + pub instruction: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to store with the agent skill. Useful for tracking provisioning context or custom labels. + pub metadata: Option>, +} + +/// Updates one or more mutable fields on the specified agent skill. All +/// parameters are optional; supply only the fields you want to change. +/// +/// When `template` is provided, the platform re-resolves that skill template +/// and re-points the skill's underlying config in place. The skill's current +/// status is preserved. Any `instruction` or `metadata` supplied alongside +/// `template` override the template's defaults. +/// +/// Requires an app-scoped API key. The skill must belong to the authenticated +/// app's scope. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentSkillsAgentSkillInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Plain-text instruction override for this agent skill. Replaces the default instruction from the skill config. Omit to leave the current value unchanged. + pub instruction: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to store with the agent skill. Omit to leave the current value unchanged. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent skill template config ID (`cfg_...`), virtual path, or lookup key. When supplied, re-resolves the template and updates the skill's underlying config in place, refreshing template provenance while preserving the skill's current status. Any `instruction` or `metadata` values provided alongside `template` override the template defaults. + pub template: Option, +} + +/// Query parameters for get_api_v1_agent_tools. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentToolsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to tools belonging to these agents (`agi_...`). Omit to return tools across all agents in the app. Multiple values are OR'd. + pub agent: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter by tool kind. One of `"builtin"` or `"custom"`. Omit to return tools of all kinds. + pub kind: Option, +} + +/// Updates the configuration of an existing tool. All parameters are optional; +/// supply only the fields you want to change. Unspecified fields are left as-is. +/// +/// You can update both `"draft"` and `"active"` tools. Updating an active tool +/// takes effect on the next agent run; any run already in progress continues +/// with the configuration it loaded at start. +/// +/// Supplying `template` re-resolves the referenced AgentToolTemplate and patches +/// the tool in place, preserving its `status`, `lookup_key`, `kind`, and agent +/// association. Any other params you supply alongside `template` override the +/// template defaults. +/// +/// Requires app scope. The authenticated caller must own the tool's parent agent. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentToolsToolInput { + #[serde(rename = "async")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, the tool executes asynchronously and the agent does not block waiting for a result. Applies to `"custom"` tools. + pub async_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Configuration object for the built-in tool. Shape is defined by the catalog entry's `config_schema` for the tool's `builtin_tool_key`. Applies to `"builtin"` tools. + pub builtin_tool_config: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config ID (`cfg_...`) referencing the script or workflow graph that implements the tool handler. Applies to `"custom"` tools. + pub config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of what the tool does, shown to the LLM as context. Applies primarily to `"custom"` tools. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Execution handler for the tool. One of `"script"` or `"workflow_graph"`. Applies to `"custom"` tools. + pub handler_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Additional natural-language instruction provided to the LLM describing when and how to call this tool. Supplements the tool's `description`. + pub instruction: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable identifier you can use to look up this tool without its ID. Must be unique within the app. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to attach to the tool. Replaces the existing metadata when supplied. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name for the tool. Applies to `"custom"` tools. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Per-instance namespace for built-in tools that support multiple instances per agent. Stamped onto LLM-facing tool names (e.g. `"org"` produces `"org_knowledge_search"`). Must match `^[a-z][a-z0-9_]*$` and be at most 24 characters. + pub name_prefix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// JSON Schema object describing the tool's input parameters. Replaces the existing parameter schema when supplied. + pub parameters: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config ID (`cfg_...`) referencing a reusable JSON Schema definition for this tool's input parameters. Takes precedence over an inline `parameters` value. + pub parameters_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config ID or lookup key of an AgentToolTemplate. When provided, re-resolves the template and patches the tool in place, preserving its `status`, `lookup_key`, `kind`, and agent association. Other params you supply alongside `template` override the template defaults. + pub template: Option, +} + +/// Query parameters for get_api_v1_agents. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to retrieve, 1-indexed. Defaults to `1`. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of agents to return per page. Defaults to `25`. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Free-text search string matched against the agent name, org, team, and owner fields. + pub search: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) to filter by. Returns only agents owned by this user. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to filter by. Returns only agents owned by this org. + pub org_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config ID (`cfg_...`) or `lookup_key` of an AgentTemplate. Returns only agents whose last applied template matches. + pub template_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Solution config IDs (`cfg_...`) to filter by. Returns only agents whose last applied template was imported as part of any of the listed Solutions. Pass one or more IDs. + pub solution_config: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsInputAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsInputAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsInputAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsInputAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsInputProfilePicture { + /// Base64-encoded binary content of the image. + pub data: String, + /// Original filename of the image, e.g. `avatar.png`. + pub filename: String, + /// MIME type of the image, e.g. `image/png` or `image/jpeg`. + pub mime_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsInputTemplateBundleConfigsItem { + /// Full text content of the configuration file. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the configuration content, e.g. `"application/x-yaml"` or `"application/json"`. `null` if not specified. + pub content_type: Option, + /// Bundle-relative path to this config file. The path determines the config kind and its storage identity within the installation. + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsInputTemplateBundleSetupActionsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// List of other setup action identifiers that must be completed before this action becomes actionable. + pub depends_on: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Markdown-formatted instructions or context shown beneath the checklist item. `null` if not provided. + pub description: Option, + /// Category of setup step. One of `"env_var"` (configure an environment variable), `"install"` (complete an installation step), `"custom"` (a user-defined action), or `"integration"` (authorize an OAuth-backed MCP server integration). + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Kind-specific configuration for the action. For `"env_var"` steps this typically includes `key` and `scope`; for `"install"` steps it includes `installation_kind`; for `"integration"` steps it includes `mcp_server_ref`. Shape varies by `kind`. + pub params: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, this action must be completed before the checklist progress bar reaches 100%. Defaults to `true`. + pub required: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Numeric sort position controlling the display order of this action in the checklist. Defaults to `0` when not specified. + pub sort_order: Option, + /// Short human-readable label displayed in the setup checklist. + pub title: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Configuration passed to the runtime verifier to determine whether the action has been completed, e.g. `{"type": "secret_present"}`. `null` if no automated verification is configured. + pub verify_config: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsInputTemplateBundleSkillsItemFilesItem { + /// Full text content of the file. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the file content. Defaults to a value inferred from the file extension when omitted. + pub content_type: Option, + /// Path of this file relative to the skill folder root, e.g. `"skills/my-skill/helpers.md"`. + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsInputTemplateBundleSkillsItem { + /// Full text content of the `SKILL.md` file. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the `SKILL.md` content. Defaults to `text/markdown` when omitted. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Additional files nested inside the skill folder, each with its own path and content. + pub files: Option>, + /// Bundle-relative path to the skill root, which must end in `/SKILL.md` (e.g. `"skills/my-skill/SKILL.md"`). + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsInputTemplateBundleTemplate { + /// Full text content of the agent template file, typically a YAML document. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the template content. Defaults to `application/x-yaml` when omitted. + pub content_type: Option, + /// Bundle-relative path to the template file, used to derive its storage identity (e.g. `"agent.yaml"`). + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsInputTemplateBundle { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Additional configuration resources (scripts, model configs, routine templates) referenced by `config_ref` entries in the template. + pub configs: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// A string appended to the lookup key of every uploaded config and rewritten into every `config_ref` in the template body. Should be stable for a given install and unique across installs to avoid key collisions. + pub lookup_key_suffix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Post-install checklist items created alongside the agent. Each action is inserted as a pending setup step that the user must complete before the agent is fully operational. + pub setup_actions: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Skill bundles referenced by the template. Each entry includes the skill root and any supporting files. + pub skills: Option>, + /// The agent template definition to install, including its path and raw content. + pub template: PostApiV1AgentsInputTemplateBundleTemplate, +} + +/// Creates a new agent. Supports two mutually exclusive provisioning modes. +/// +/// **Template mode** — pass `template` with the ID or `lookup_key` of an existing +/// AgentTemplate config. The agent's tools, routines, skills, and installations are +/// provisioned from that template's `config_ref` entries. +/// +/// **Bundle mode** — pass `template_bundle` with a self-contained install payload +/// (AgentTemplate body plus every skill, script, and config it references). The entire +/// bundle commits in a single transaction; any failure rolls back the whole install and +/// the response includes `installed_configs[]` — one entry per persisted config. +/// +/// Pass exactly one of `template` or `template_bundle`. If neither is supplied, `name` +/// is required and a blank agent is created. Requires authentication; when called under +/// a developer app scope (`/developer/apps/:app/...`), the caller must hold the app scope +/// for the target app. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list controlling which users, teams, or orgs can read or manage this agent. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of what the agent does. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address assigned to the agent. Used as the agent's contact identity. + pub email: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// System-prompt identity string describing who the agent is. Passed verbatim to the model on each conversation turn. + pub identity: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable, unique slug used to look up this agent by name instead of ID. Must be unique within the owning app or org. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map stored on the agent. Not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Default AI model identifier for this agent, e.g. `claude-sonnet-4-5`. Overridden per-request when the caller specifies a model. + pub model: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name for the agent. Required when neither `template` nor `template_bundle` is provided. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) that should own this agent. Mutually exclusive with `team` and `user`. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Free-form label identifying the source or author of the agent, e.g. a user ID, a deploy pipeline, or a slug. + pub originator: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Phone number assigned to the agent in E.164 format, e.g. `+15550001234`. + pub phone_number: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture to attach to the agent. All three subfields are required when this object is present. + pub profile_picture: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) that should own this agent. Mutually exclusive with `org` and `user`. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID (`cfg_...`) or `lookup_key` of an existing AgentTemplate config to provision from. Mutually exclusive with `template_bundle`. + pub template: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Self-contained install bundle containing an AgentTemplate plus all referenced skills and configs. The entire bundle is committed atomically. Mutually exclusive with `template`. + pub template_bundle: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) that should own this agent. Mutually exclusive with `org` and `team`. + pub user: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentsAgentInputAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentsAgentInputAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentsAgentInputAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentsAgentInputAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentsAgentInputProfilePicture { + /// Base64-encoded binary content of the image. + pub data: String, + /// Original filename of the image, e.g. `avatar.png`. + pub filename: String, + /// MIME type of the image, e.g. `image/png` or `image/jpeg`. + pub mime_type: String, +} + +/// Updates one or more fields on an existing agent. Only the fields you supply are +/// changed; omitted fields retain their current values. +/// +/// To clear the agent's default model, pass `model` as an empty string. The +/// authenticated caller must own the agent or hold write permissions within its owning +/// org or team. When called under a developer app scope, the caller must hold the app +/// scope for the target app. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentsAgentInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement access control list. Fully replaces the existing ACL. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New description of what the agent does. Pass an empty string to clear it. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New email address for the agent. + pub email: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement identity system-prompt string describing who the agent is. + pub identity: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New `lookup_key` slug. Must be unique within the owning app or org. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement key-value metadata map. The entire map is replaced, not merged. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New default AI model identifier, e.g. `claude-sonnet-4-5`. Pass an empty string to clear the agent's default model. + pub model: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New display name for the agent. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to transfer ownership to. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement originator label identifying the source or author of the agent. + pub originator: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New phone number for the agent in E.164 format, e.g. `+15550001234`. + pub phone_number: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement profile picture. All three subfields are required when this object is present. + pub profile_picture: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) to transfer ownership to. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) to transfer ownership to. + pub user: Option, +} + +/// Query parameters for get_api_v1_agents__agent_agent_health_actions. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentsAgentAgentHealthActionsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to actions from one or more lifecycle stages. Accepted values: `"setup"` (actions created during agent installation) and `"health"` (ongoing health checks). Omit to return actions from all stages. + pub source: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to actions in one or more statuses. Accepted values: `"pending"`, `"completed"`, `"skipped"`, and `"degraded"`. Omit to return actions in all statuses. + pub status: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to actions of one or more kinds. Accepted values: `"env_var"` (a required secret or config value), `"install"` (an OAuth or integration install step), and `"custom"` (a platform-defined check). Omit to return all kinds. + pub kind: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentRoutinesInputAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentRoutinesInputAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentRoutinesInputAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentRoutinesInputAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentRoutinesInputMessagePolicy { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Required and non-empty for private visibility. Sources are additive. Routine owner includes the agent owner and optional user co-owner. + pub recipients: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message visibility. One of `default` or `private`. + pub visibility: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentRoutinesInputPresetConfigLlm { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Provider-prefixed model identifier for this routine or step, e.g. `"openrouter/anthropic/claude-sonnet-latest"`. When omitted, the agent's default model is used. + pub model: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentRoutinesInputPresetConfig { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Custom task or behavior instructions for the preset (max 10,000 chars). + pub instructions: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// LLM invocation settings (e.g. a `model` override for this routine/step). + pub llm: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Session mode: `stateless` (default, new session per trigger) or `session` (find-or-create a persistent session scoped by `session_scope`). + pub session_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `session_mode` is `session`, controls session scoping: `per_user` (default), `per_key`, `per_org`, or `global`. + pub session_scope: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// IDs of structured message templates that constrain the agent's responses to predefined structured formats. + pub structured_message_template_ids: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentRoutinesInputStepsItemPresetConfigLlm { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Provider-prefixed model identifier for this routine or step, e.g. `"openrouter/anthropic/claude-sonnet-latest"`. When omitted, the agent's default model is used. + pub model: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentRoutinesInputStepsItemPresetConfig { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Custom task or behavior instructions for the preset (max 10,000 chars). + pub instructions: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// LLM invocation settings (e.g. a `model` override for this routine/step). + pub llm: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Session mode: `stateless` (default, new session per trigger) or `session` (find-or-create a persistent session scoped by `session_scope`). + pub session_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `session_mode` is `session`, controls session scoping: `per_user` (default), `per_key`, `per_org`, or `global`. + pub session_scope: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// IDs of structured message templates that constrain the agent's responses to predefined structured formats. + pub structured_message_template_ids: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentRoutinesInputStepsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of a saved config to use as the handler body. Required when `handler_type` is `"workflow_graph"`; also accepted for `"script"` as an alternative to an inline `script` value. + pub config: Option, + /// Execution handler for this step. One of `"preset"`, `"script"`, or `"workflow_graph"`. + pub handler_type: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional key-value map binding outputs from prior steps to this step's input variables. + pub inputs: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional label for this step. Must be unique within the chain when provided. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Error handling policy for this step. One of `"halt"` (default), `"continue"`, or `"retry"`. + pub on_error: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key under which this step's result is stored and addressable by downstream steps. Defaults to `name` when omitted. + pub output_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Configuration overrides for the preset, using the same shape as the routine-level `preset_config`. You may include an `llm` key to override the agent's default model for this step. `null` if not provided. + pub preset_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Name of the preset to invoke. Required when `handler_type` is `"preset"`. + pub preset_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Inline script source code to execute. Used when `handler_type` is `"script"` and no `config` is provided. + pub script: Option, +} + +/// Creates a new routine and attaches it to the specified agent. Routines define +/// how an agent responds to events or a cron schedule; the `handler_type` controls +/// which execution model is used. +/// +/// The routine is created in `"draft"` status by default. To start processing +/// events immediately, either pass `status: "active"` or call the activate +/// endpoint after creation. Scheduled routines must run no more frequently than +/// once per hour. Requires app scope. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentRoutinesInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list governing who can read or manage this routine. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Workflow config ID (`cfg_...`). Required when `handler_type` is `"workflow_graph"`. + pub config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional human-readable description of what this routine does. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Mapping of event types to trigger configuration. Each key is an event type string; each value is an object with a `"filters"` map and an optional `"dedupe_key_path"` (a JSON path used to deduplicate events, e.g. `"$.thread.id"`). + pub event_config: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Event type that triggers this routine. Deprecated — use `event_config` instead. + pub event_type: Option, + /// Execution model for this routine. One of `"workflow_graph"`, `"script"`, `"preset"`, or `"chain"`. + pub handler_type: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable, unique key you assign to this routine for deterministic lookup. Must be unique within the app. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Visibility and explicit recipient selection for messages emitted by the routine. + pub message_policy: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata you can attach to the routine. Not interpreted by the platform. + pub metadata: Option>, + /// Human-readable display name for the routine. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Configuration passed to the preset at runtime. Used when `handler_type` is `"preset"`. + pub preset_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Name of the registered preset to use. Required when `handler_type` is `"preset"`. + pub preset_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Cron expression for time-triggered routines (e.g. `"0 9 * * 1"`). Must not be more frequent than once per hour. + pub schedule: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Inline script source. Required when `handler_type` is `"script"`. + pub script: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Initial lifecycle status. One of `"draft"` or `"active"`. Defaults to `"draft"`. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Ordered list of steps for a chain handler. Required when `handler_type` is `"chain"`; must be omitted or empty otherwise. Each step must have exactly one handler body field (`preset_name`, `script`, or `config`) matching that step's `handler_type`. + pub steps: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Context in which the routine is triggered. One of `"chat_session"` or `"event"`. Defaults to `"event"`. + pub trigger_context: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional co-owner user ID (`usr_...`). When set, that user shares authority over this routine (view/modify/delete) without needing to administer the parent agent. Must be supplied explicitly — the caller's identity is never auto-stamped as co-owner. + pub user: Option, +} + +/// Query parameters for get_api_v1_agents__agent_export. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentsAgentExportParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, strips instance-unique identity fields (`email`, `phone_number`) from the exported template so it can be reused as a generic blueprint. + pub remove_identity: Option, +} + +/// Performs a semantic search over an agent's knowledge base and returns a ranked, +/// `kind`-discriminated list of matching items. +/// +/// Two item kinds may appear in `data`: +/// +/// - `"chunk"` — chunk-level results from the agent's context store. Present for all agents. +/// - `"document"` — document-level results. Present only when the agent has an active +/// `archastro/knowledge` installation. +/// +/// Results from both kinds are scored with Reciprocal Rank Fusion (RRF), normalized to +/// be comparable across kinds, then merged into a single ranked list. On a relevance tie, +/// chunks appear before documents. The total number of results is capped at `max_results` +/// across both kinds. +/// +/// Use `mode` to choose the retrieval strategy: `"hybrid"` (default) combines vector and +/// full-text search; `"vector"` and `"fulltext"` select each strategy independently. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentSearchInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum total results to return across all kinds. Chunks and documents are ranked together and the list is capped at this value. Defaults to `20`; maximum is `100`. + pub max_results: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Cosine-similarity floor for the vector leg, 0.0-1.0, applied to both chunk and document results. Candidates below it are discarded before ranking, so a high value trades recall for precision. Pass `0.0` to disable the floor when a missed match costs more than a weak one — note that with no floor every query returns results, so an empty response can no longer be read as "no match". Omit to use the default. + pub min_similarity: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Retrieval strategy. One of `"hybrid"` (default), `"vector"`, or `"fulltext"`. + pub mode: Option, + /// Natural-language search query used to retrieve relevant knowledge items. + pub query: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When set, restricts results to items indexed within the last N days. + pub recency_days: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of source-type slugs used to filter chunk results, e.g. `["web", "file"]`. Omit to include all source types. + pub source_types: Option>, +} + +/// Contract-defined alternatives for PostApiV1AgentsAgentSearchResponseDataItem. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum PostApiV1AgentsAgentSearchResponseDataItem { + /// Variant1 union variant. + Variant1(Value), + /// Variant2 union variant. + Variant2(Value), +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentSearchResponse { + /// Ranked list of matching knowledge items. Each item is a `kind`-discriminated union — either `"chunk"` (always present) or `"document"` (present only when the agent has an active `archastro/knowledge` installation). Sorted by relevance descending; capped at `max_results` total across both kinds. + pub data: Vec, +} + +/// Contract-defined values for PostApiV1AgentsAgentThreadsInputThreadMembersItemType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum PostApiV1AgentsAgentThreadsInputThreadMembersItemType { + /// The user wire value. + #[serde(rename = "user")] + User, + /// The agent wire value. + #[serde(rename = "agent")] + Agent, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentThreadsInputThreadMembersItem { + /// Public user (`usr_...`) or agent (`agt_...`) ID matching `type`. + pub id: String, + #[serde(rename = "type")] + /// Member kind. Use `user` for a user ID or `agent` for an agent ID. + pub type_: PostApiV1AgentsAgentThreadsInputThreadMembersItemType, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentThreadsInputThreadProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Base64-encoded image bytes. + pub data: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the uploaded image, used for display and content-type inference. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. + pub mime_type: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentThreadsInputThreadSettings { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured. + pub agent_enabled: Option, +} + +/// Contract-defined values for PostApiV1AgentsAgentThreadsInputThreadVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum PostApiV1AgentsAgentThreadsInputThreadVisibility { + /// The team wire value. + #[serde(rename = "team")] + Team, + /// The restricted wire value. + #[serde(rename = "restricted")] + Restricted, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentThreadsInputThread { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, provisions a legacy chat agent alongside the thread. Only needed for integrations that depend on the pre-v2 agent model. + pub create_legacy_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional longer description of the thread's purpose. `null` if not provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, the thread is hidden from the default thread list and accessible only by direct link or ID. + pub is_unlisted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Client-assigned unique key for idempotent creation or later lookup. Must be unique within the owning organization. + pub key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Users and agents to add atomically when the thread is created. Each target must pass the same authorization rules as a post-creation member add. Slack mirror threads reject non-empty caller-supplied rosters because their membership is sync-owned. + pub members: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value pairs stored alongside the thread. Values must be strings or numbers. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, push and in-app notifications for this thread are suppressed for the creating user. + pub muted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization to create the thread under. Defaults to the authenticated user's primary organization when omitted. + pub org_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional profile image for the thread, provided as a base64-encoded payload. + pub profile_picture: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Configuration overrides for the thread, such as AI model selection and context window settings. + pub settings: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional URL-safe identifier. Derived from the title when omitted and unique within the thread owner. + pub slug: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name for the thread. `null` if omitted, which causes the thread to be untitled. + pub title: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Thread visibility. A team-owned thread with members must explicitly use `restricted` or `private`. User- and agent-owned threads with members default to `private` and reject every other value. + pub visibility: Option, +} + +/// Creates a new thread owned by the specified agent. The thread is scoped to the +/// agent's identity and is immediately available for messaging. +/// +/// The authenticated caller must have access to the agent's parent app. If your +/// API key is scoped to a specific app, pass that app's ID via the `app` parameter. +/// Attempting to create a thread for an agent you cannot access returns 404. +/// +/// By default the platform may send an automatic welcome message into the new +/// thread. Pass `skip_welcome_message: true` to suppress this behavior. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentThreadsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, suppresses the automatic welcome message that the platform sends when a new thread is created. Defaults to `false`. + pub skip_welcome_message: Option, + /// Attributes for the new thread. See ThreadCreateParams for available fields. + pub thread: PostApiV1AgentsAgentThreadsInputThread, +} + +/// Contract-defined values for PostApiV1AgentsAgentUpgradeInputMode. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum PostApiV1AgentsAgentUpgradeInputMode { + /// The reapply wire value. + #[serde(rename = "reapply")] + Reapply, + /// The replace wire value. + #[serde(rename = "replace")] + Replace, +} + +/// Upgrades an existing agent by reconciling it against an AgentTemplate from a +/// Solution. Supports two modes: +/// +/// - `"reapply"` (default) — re-applies the agent's currently tracked template, +/// picking up any changes the template author has made since the last apply. +/// - `"replace"` — moves the agent to a different template. `template` is required +/// in this mode. +/// +/// Set `dry_run: true` to compute and return the full upgrade diff (adds, updates, +/// removes, noops) without writing any changes. The response includes a +/// `review_fingerprint` you can pass back via `expected_review_fingerprint` on the +/// live apply to guard against the diff changing between review and execution. +/// +/// Safe overrides (`name`, `description`, `email`, `phone_number`, `metadata`, +/// `identity`, `originator`, `model`) let you pin instance-specific values that +/// should not be overwritten by the template during the upgrade. +/// +/// The authenticated caller must own the agent or hold write permissions within its +/// owning org or team. When called under a developer app scope, the caller must hold +/// the app scope for the target app. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentUpgradeInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Instance-specific description override. Pins this value so the template upgrade does not overwrite it. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, computes and returns the full upgrade diff without persisting any changes. Use with `expected_review_fingerprint` to guard the live apply. + pub dry_run: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Instance-specific email address override. Pins this value so the template upgrade does not overwrite it. + pub email: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stale-review guard. Pass the `review_fingerprint` returned by a prior `dry_run` response to ensure the diff has not changed between review and live apply. Returns an error if the fingerprint no longer matches. + pub expected_review_fingerprint: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Instance-specific identity system-prompt override. Pins this value so the template upgrade does not overwrite it. + pub identity: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Instance-specific metadata override. Pins this value so the template upgrade does not overwrite it. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Upgrade mode. `"reapply"` (default) refreshes the agent's tracked template; `"replace"` moves the agent to a different template (requires `template`). + pub mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Instance-specific default model override. Pins this value so the template upgrade does not overwrite it. Pass an empty string to clear the model. + pub model: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Instance-specific name override. Pins this value so the template upgrade does not overwrite it. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Instance-specific originator label override. Pins this value so the template upgrade does not overwrite it. + pub originator: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Instance-specific phone number override in E.164 format. Pins this value so the template upgrade does not overwrite it. + pub phone_number: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID (`cfg_...`) or `lookup_key` of the target AgentTemplate config. Optional in `"reapply"` mode; required in `"replace"` mode. + pub template: Option, +} + +/// Creates and provisions a new computer resource associated with the specified +/// agent. The computer is allocated in the requested region (defaulting to `iad`) +/// and its status transitions from `provisioning` to `running` once it is ready. +/// +/// Requires an app-scoped API key. The agent identified by `agent` must belong +/// to the same app. Supplying a `lookup_key` lets you retrieve this computer +/// later without storing its ID — the key must be unique within the app. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentComputersInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Provider-specific configuration for the computer. Supported keys vary by provider. A top-level `provider` takes precedence over `config.provider`. + pub config: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable, user-defined key for this computer. Must be unique within the app. Use it to look up the computer without storing its ID. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to attach to the computer. Not interpreted by the platform; returned as-is on all subsequent reads. + pub metadata: Option>, + /// Human-readable display name for the computer. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Compute backend for the computer: `"sprites"` (Fly Sprites, the default) or `"vercel"` (Vercel Sandbox). Folded into `config.provider`. + pub provider: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Region in which to provision the computer, e.g. `"iad"`. Defaults to `"iad"` when omitted. + pub region: Option, +} + +/// Creates a new environment variable for the specified agent. The variable is +/// stored securely and the plaintext `value` is never returned after creation; +/// subsequent reads return a masked representation showing only the last four +/// characters. +/// +/// The authenticated user must have access to the agent's parent app. Pass the +/// app scope via the `app` parameter when calling with an API key that is scoped +/// to a specific app. Each `key` must be unique within the agent; attempting to +/// create a duplicate key returns a validation error. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentEnvVarsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional human-readable note describing what the variable is used for. + pub description: Option, + /// Environment variable name, e.g. `WEBHOOK_SECRET`. Must be unique within the agent. + pub key: String, + /// Plaintext secret value to store. The value is encrypted at rest and never returned in full. + pub value: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentInstallationsInputIntegration { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// OAuth access token or static API key used by `oauth` providers to authenticate requests on behalf of the user. + pub access_token: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// External installation identifier used by `app_installation` providers, e.g. a GitHub App installation ID or a Slack team ID. + pub installation_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary provider-specific metadata, e.g. `{"bot_user_id": "U012AB3CD"}` for Slack. Stored alongside the integration and made available to connector logic. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// OAuth refresh token used to obtain a new `access_token` when the current one expires. Omit for providers that do not issue refresh tokens. + pub refresh_token: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Provider-specific workspace or team identifier, e.g. a Slack workspace slug. Used to scope the integration to a particular workspace. + pub workspace_key: Option, +} + +/// Creates a new installation for an agent, connecting it to an external service or +/// enablement channel via the specified `kind`. The installation begins in a pending +/// state unless an integration is supplied at creation time, in which case it is +/// activated immediately. +/// +/// Supply `shared_integration` to bind an existing org- or app-level integration, or +/// supply `integration` to create a new integration inline and activate the installation +/// in a single request. Supplying both fields returns 422. +/// +/// Use `lookup_key` to assign a stable identifier you can reference later in knowledge +/// search `source_refs`. The key must be unique within the app, org, and sandbox +/// combination. The caller must have app scope for the app that owns the agent. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentInstallationsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Kind-specific configuration object. Shape varies by `kind`; omit if the kind requires no initial configuration. + pub config: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Inline integration fields to create for `integration/*` kinds. When provided, a new Integration record is created and the installation is activated immediately. Mutually exclusive with `shared_integration`. + pub integration: Option, + /// Installation kind that determines the external service being connected. Examples: `"enablement/github_app"`, `"enablement/slack_bot"`, `"integration/github"`, `"integration/gmail"`, `"web/site"`. Use the List Kinds endpoint to retrieve all supported values. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable identifier you assign to this installation. Propagated to backing context source rows so they can be referenced via knowledge search `source_refs`. Must contain only lowercase letters, numbers, underscores, or hyphens (max 100 characters). Must be unique within the same app, org, and sandbox combination. Omit to skip stable referencing. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of an existing shared org- or app-level integration to bind to this installation. Mutually exclusive with `integration`. + pub shared_integration: Option, +} + +/// Query parameters for get_api_v1_agents__agent_agent_tools. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentsAgentAgentToolsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter by tool kind. One of `"builtin"` or `"custom"`. Omit to return tools of all kinds. + pub kind: Option, +} + +/// Creates a new tool and attaches it to the specified agent. Tools can be +/// either `"builtin"` (a platform-provided capability identified by +/// `builtin_tool_key`) or `"custom"` (a caller-defined tool with its own name, +/// description, parameter schema, and handler). +/// +/// New tools are created in `"draft"` status by default unless `status: +/// "active"` is explicitly supplied. Draft tools are not exposed to the LLM +/// during agent runs; call the activate endpoint to promote them. +/// +/// For built-in tools that support multiple instances per agent (those whose +/// catalog entry has a `multi_instance_mode`), supply `name_prefix` to +/// namespace the LLM-facing tool names. Requires app scope. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentAgentToolsInput { + #[serde(rename = "async")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, the tool executes asynchronously and the agent does not block waiting for a result. Applies to `"custom"` tools. + pub async_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Configuration object for the built-in tool. Shape is defined by the catalog entry's `config_schema` for the chosen `builtin_tool_key`. Applies only to `"builtin"` tools. + pub builtin_tool_config: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key identifying the built-in tool type to add (e.g. `"knowledge_search"`). Required when `kind` is `"builtin"`. Must match a key in the tool catalog. + pub builtin_tool_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config ID (`cfg_...`) referencing the script or workflow graph that implements the tool handler. Applies to `"custom"` tools. + pub config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of what the tool does. Shown to the LLM as context. Applies primarily to `"custom"` tools. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Execution handler for the tool. One of `"script"` or `"workflow_graph"`. Applies to `"custom"` tools. + pub handler_type: Option, + /// Tool kind. One of `"builtin"` or `"custom"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional stable identifier you can use to look up this tool without its ID. Must be unique within the app. Useful for idempotent provisioning. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to attach to the tool. Not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name for the tool. Required when `kind` is `"custom"`. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Per-instance namespace for built-in tools that support multiple instances per agent. Stamped onto LLM-facing tool names (e.g. `"org"` produces `"org_knowledge_search"`). Must match `^[a-z][a-z0-9_]*$` and be at most 24 characters. Required for `"namespaced"` multi-instance tools; omit for single-instance tools. + pub name_prefix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// JSON Schema object describing the tool's input parameters. Used by the LLM to construct valid tool calls. Applies to `"custom"` tools. + pub parameters: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Initial status of the tool. One of `"draft"` or `"active"`. Defaults to `"draft"` when omitted. + pub status: Option, +} + +/// Query parameters for get_api_v1_agents__agent_agent_working_memory. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentsAgentAgentWorkingMemoryParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to retrieve, starting at 1. Defaults to 1. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of entries to return per page. Defaults to 25. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Substring filter applied to entry keys (case-insensitive). Omit to return all keys. + pub search: Option, +} + +/// Updates the value and/or expiry of an existing working memory entry. Only +/// the fields you supply are changed; omitted fields retain their current +/// values. The entry `key` cannot be changed after creation — delete the entry +/// and let the agent (or a future create call) write a new one instead. +/// +/// Pass `expires_at` as `null` to remove the expiry so the entry no longer +/// expires. Expired entries can still be updated; they stay hidden from list +/// results until their expiry is in the future again. +/// +/// Requires an app-scoped API key. The authenticated caller must be able to +/// modify the agent that owns the entry. Returns 403 if the key is not +/// app-scoped or the caller lacks modify access, and 404 if the agent or entry +/// does not exist within the accessible scope. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1AgentsAgentAgentWorkingMemoryEntryInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New expiry for the entry (ISO 8601). Pass `null` to remove the expiry so the entry never expires. Omit to keep the current expiry. + pub expires_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement string value to store under the entry's key. Maximum 65,536 characters. + pub value: Option, +} + +/// Query parameters for get_api_v1_agents__agent_schedules. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentsAgentSchedulesParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results by schedule status. One of `"active"`, `"paused"`, `"completed"`, `"cancelled"`, or `"expired"`. Omit to return schedules in all statuses. + pub status: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentsAgentSchedulesResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this schedule (`agi_...`). + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the application the schedule belongs to (`dap_...`). + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the schedule was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Standard cron expression defining the recurrence pattern (e.g. `"0 9 * * 1"`). Present only when `schedule_type` is `"recurring"`. `null` for one-time schedules. + pub cron_expression: Option, + /// Schedule ID (`asc_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The task description the agent will execute when this schedule fires. + pub instructions: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// UTC datetime of the most recent successful execution. `null` if the schedule has never run. + pub last_run_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of times a recurring schedule may fire before automatically transitioning to `"completed"`. `null` means no limit. + pub max_runs: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value pairs attached to the schedule by the agent. Not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// UTC datetime of the next planned execution. `null` if the schedule has completed, been cancelled, or has not yet been computed. + pub next_run_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of times this schedule has fired. + pub run_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Determines how the schedule repeats. `"once"` fires a single time at `scheduled_at` then transitions to `"completed"`. `"recurring"` fires on the `cron_expression` and reschedules automatically. + pub schedule_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The exact UTC datetime at which a one-time schedule fires. Present only when `schedule_type` is `"once"`. `null` for recurring schedules. + pub scheduled_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current lifecycle status of the schedule. One of `"active"` (will fire as planned), `"paused"` (temporarily suspended), `"completed"` (has run its last execution), `"cancelled"` (manually stopped), or `"expired"` (past its valid window). + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Thread ID (`thr_...`) this schedule is bound to. When set, the scheduled task is delivered into the thread rather than creating a new session. `null` for session-based schedules. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// IANA timezone name used to interpret the cron expression or `scheduled_at` (e.g. `"America/New_York"`). Defaults to `"Etc/UTC"`. + pub timezone: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the schedule was last modified (ISO 8601). + pub updated_at: Option>, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentsAgentSchedulesResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of agent schedule objects matching the query. + pub data: Option>, +} + +/// Query parameters for get_api_v1_agents__agent_work_items. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AgentsAgentWorkItemsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional durable execution ID filter. + pub execution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum work items per page. Defaults to 50; maximum is 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor for the next page of older queued work. + pub after_cursor: Option, +} + +/// Atomically claims the oldest queued or lease-expired item. To resume after a +/// harness restart, pass both the saved `work_item` and the same `lease_owner`; +/// the server refreshes that active lease without incrementing its attempt. +/// Returns `data: null` when no eligible item exists, including when another +/// lease owns the explicitly requested item. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AgentsAgentWorkItemsClaimInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional durable execution ID filter. + pub execution: Option, + /// Caller-generated random UUID lease token. + pub lease_owner: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lease duration from 15 through 3600 seconds. Defaults to 300. + pub lease_seconds: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Saved work item ID to resume or reclaim. + pub work_item: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1ArtifactsArtifactInputFile { + /// Base64-encoded binary content. + pub data: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename for the uploaded file. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the uploaded file. + pub mime_type: Option, +} + +/// Updates the metadata and, optionally, the file content of an existing artifact. +/// This endpoint uses optimistic concurrency control: you must supply the artifact's +/// current `version` number as `from_version`. If another update has incremented the +/// version since you last fetched the artifact, the request returns 409. +/// +/// To replace the artifact's file, include a nested `file` object with Base64 +/// `data`, `filename`, and `mime_type`. Omitting `file` leaves the existing file +/// unchanged. The authenticated user or developer must have write access to the +/// artifact's owner. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1ArtifactsArtifactInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New description for the artifact. Omit to leave the existing description unchanged. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement file payload. Omit to leave the current file unchanged. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Legacy flat Base64 file content. Prefer `file.data`. + pub file_content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Legacy flat MIME type. Prefer `file.mime_type`. + pub file_content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Legacy flat filename. Prefer `file.filename`. + pub file_name: Option, + /// The artifact's current version number, used for optimistic concurrency control. Returns 409 if this value does not match the server's current version. + pub from_version: i64, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New display name for the artifact. Omit to leave the existing name unchanged. + pub name: Option, +} + +/// Query parameters for get_api_v1_artifacts__artifact_content. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ArtifactsArtifactContentParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Version number to retrieve. Omit to return the artifact's current version. + pub version: Option, +} + +/// Query parameters for get_api_v1_automation_runs__automation_run_journal. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AutomationRunsAutomationRunJournalParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of entries to return. Defaults to 50; maximum is 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor from the previous response's `after_cursor` field. + pub after_cursor: Option, +} + +/// Typed events emitted by get_api_v1_automation_runs__automation_run_stream. +#[derive(Debug, Clone, PartialEq)] +pub enum GetApiV1AutomationRunsAutomationRunStreamEvent { + /// Contract-defined stream event. + RunUpdate(AutomationRun), +} +impl SseDecode for GetApiV1AutomationRunsAutomationRunStreamEvent { + fn decode(event: &str, data: &str) -> Result { + match event { + "run_update" => Ok(Self::RunUpdate(serde_json::from_str(data)?)), + other => Err(crate::Error::UnknownSseEvent(other.to_owned())), + } + } +} + +/// Triggers a single run of an automation that has `type: "invoked"`. Returns +/// the resulting automation run object, which you can use to poll or display +/// run status. +/// +/// Both server-to-server (secret key) and user (publishable key + JWT) auth +/// are supported. The automation's `invoke_auth` setting controls which auth +/// modes are accepted; requests using an unsupported mode are rejected with +/// 403. For server-to-server callers the run executes under the identity +/// configured in the automation's `run_as_user` or `run_as_agent` fields. For +/// authenticated user callers the invoking user's identity is used +/// automatically. +/// +/// If you supply an `idempotency_key`, a second request with the same key +/// returns the existing run rather than creating a new one. +/// +/// ## Body fields +/// +/// * `payload` — free-form invoke input. **This is the workflow parameters**: +/// validated against `input_schema` when configured, stored as +/// `event_payload`, and becomes the workflow `$` after trigger unwrap +/// (e.g. `{{$.bug}}` for `{"bug":"upload fails"}`). +/// * `participants` — optional map of symbolic participant refs to agent ids +/// for distributed `embed_agent` nodes, e.g. +/// `{"investigator":"agi_...","evaluator":"agi_..."}`. Stored in the +/// run's top-level `participants` field (not inside free-form payload) and +/// exposed to workflows through their system context. +/// +/// Same top-level `payload` + `participants` shape as routine invoke. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AutomationsAutomationInvokeInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Unique key to deduplicate concurrent or retried invocations. A second request with the same key returns the existing run instead of creating a new one. + pub idempotency_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Map of symbolic participant refs to agent ids (`agi_...` or UUID) for distributed embed_agent handoffs. Stored in the run's top-level `participants` field. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Free-form invoke input — the workflow parameters. Validated against the automation's `input_schema` when configured. Stored as `event_payload` and becomes the workflow `$` after trigger unwrap (e.g. `{{$.bug}}`). + pub payload: Option>, +} + +/// Creates a bug report or freeform feedback entry on behalf of the authenticated user. +/// The `description` is stored in full; the `context` blob is stored verbatim and surfaced +/// during triage. Callers should include relevant session identifiers (URL, thread ID, etc.) +/// in `context` to speed up reproduction. +/// +/// This endpoint requires authentication. Submissions are rate-limited to 10 reports per +/// user per hour; exceeding that limit returns 429. The `client` value must be one of the +/// recognised string identifiers listed below — an unrecognised value returns 400. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1BugReportsInput { + /// Identifier of the submitting client. One of `"agent_network_web"`, `"cli"`, or `"developer_portal"`. + pub client: String, + /// Build SHA or package version of the client. + pub client_version: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional client-shaped context blob; ≤5 KB serialized. Stored verbatim and surfaced for triage — clients commonly include url, user_agent, thread_id, message_id, etc. + pub context: Option>, + /// Freeform report text. 1–10,000 chars after trim. + pub description: String, +} + +/// Query parameters for get_api_v1_config. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) whose configs to list. Mutually exclusive with `user` and `agent`. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) whose configs to list. Defaults to the current user when the viewer is a user and no owner selector is provided. Mutually exclusive with `team` and `agent`. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) whose configs to list. Mutually exclusive with `team` and `user`. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to configs of this kind, e.g. `"Agent"` or `"APITool"`. Omit to return configs of all non-private kinds. + pub kind: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter to the config with exactly this `lookup_key`. Returns at most one result. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter to configs whose `virtual_path` starts with this prefix, e.g. `"my-agent/"`. Useful for listing files within a folder. + pub path_prefix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter to configs that are children of any of the listed parent config IDs (`cfg_...`). Pass a single ID to retrieve all children of one bundle. + pub parents: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter to configs that were imported as part of any of the listed solution config IDs (`cfg_...`). Useful for identifying all files that arrived with a given solution. + pub parent_solutions: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigResponseDataItemCurrentVersion { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable summary of what changed in this version, as provided by the author. `null` if no description was supplied. + pub change_description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// SHA-256 digest of the raw config content encoded as `sha256:`. Uses the same algorithm as the CLI `computeContentHash` helper. `null` for versions created before this field was introduced. + pub content_hash: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this config version was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary structured metadata stored alongside this version. `null` when no extra data was provided. + pub data: Option>, + /// Config version ID (`cfv_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) that owns this config version. `null` for personal configs. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sandbox ID (`sbx_...`) this version was saved under. `null` for production configs. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config version ID (`cfv_...`) for the Solution version this config version was installed from. `null` for standalone configs and legacy rows. + pub source_solution_config_version: Option, + /// Monotonically increasing integer identifying this version within the config. Starts at 1. + pub version_number: i64, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) associated with this config. `null` if not linked to an agent. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this config was first created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The most recently saved version of this config. `null` if the config has never been saved with content. + pub current_version: Option, + /// Config ID (`cfg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this config has been archived. Archived configs are hidden from default listings but remain accessible by ID. + pub is_archived: Option, + /// Type of config, e.g. `"Agent"` or `"APITool"`. Determines which fields and validation rules apply. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable, user-defined key used to look up this config without knowing its ID. `null` if not set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the config's content, e.g. `"text/yaml"`. `null` if not determined. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) this config belongs to. `null` for configs not scoped to an org. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Parent bundle config ID (`cfg_...`). Present only for configs that are children of a bundle; `null` otherwise. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID (`cfg_...`) of the solution config this config was imported with. `null` if the config was not imported via a solution. + pub parent_solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Raw file content as a string. Populated only for system configs; `null` for user-owned configs. + pub raw_content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Path of this config relative to its parent bundle root. Present only for bundle children; `null` otherwise. + pub relative_path: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sandbox identifier this config belongs to. `null` for production configs. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`tea_...`) that owns this config. `null` for personal (user-scoped) configs. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this config was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) who owns this config. `null` for team-scoped configs. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Logical path uniquely identifying this config within its team, e.g. `"agents/my-agent.yaml"`. `null` for configs without an explicit path. + pub virtual_path: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigResponse { + /// Array of config objects matching the query. + pub data: Vec, +} + +/// Creates a new config and its first version. Returns 201 on success. +/// +/// A config is uniquely identified within an app + org scope by its +/// `virtual_path` or `lookup_key`. Creating a config at a path that already +/// exists (including archived configs) returns 409. To adopt an existing config +/// at that path and re-own it instead, pass `take_ownership: true` — this +/// requires modify rights on the existing row (developer or all-powerful viewer). +/// +/// The owner is resolved from the explicit selector params (`team`, `user`, +/// `agent`, or `system`). Developer and all-powerful viewers default to system +/// ownership when no explicit selector is provided. Exactly one owner selector +/// may be set; conflicting selectors return 422. +/// +/// Requires app scope. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ConfigInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) to assign as the config owner. Mutually exclusive with `team`, `user`, and `system`. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of this initial version, stored on the version record. + pub change_description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata stored on the version alongside the content. + pub data: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Encoding of `raw_content`. Omit or set `"raw"` for literal content; set `"base64"` when sending binary content such as images or PDFs in JSON. + pub data_encoding: Option, + /// Config kind that determines the schema and behavior of the config, e.g. `"Agent"` or `"APITool"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional stable key for looking up this config independent of its `virtual_path`. Must be unique within the app + org scope across all owners. + pub lookup_key: Option, + /// MIME type of `raw_content`, e.g. `"application/x-yaml"` or `"application/json"`. + pub mime_type: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to scope the config to a specific org. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Parent config ID (`cfg_...`) for bundle children, e.g. files belonging to a Skill. Required together with `relative_path` when creating a child config. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Solution config ID (`cfg_...`) that this config was imported with. Records provenance for configs that arrive as part of a solution bundle. + pub parent_solution: Option, + /// Raw content bytes for the first version. Accepted formats depend on `mime_type`; typical values are YAML or JSON text. + pub raw_content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Path of this config within its parent bundle, e.g. `"prompts/system.md"`. Required when `parent` is set. + pub relative_path: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Set `true` to create a system-owned config (no team, user, or agent owner). Requires a developer, all-powerful, or app system-user viewer, or an org admin creating an org-scoped system config. Mutually exclusive with `team`, `user`, and `agent`. + pub system: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true` and a config already exists at the specified `virtual_path` or `lookup_key` under a different owner, adopt that config rather than returning 409: the existing row is re-owned to the requested owner, unarchived if necessary, and this content is saved as its next version. Requires modify rights on the existing row (developer or all-powerful viewer). + pub take_ownership: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) to assign as the config owner. Mutually exclusive with `user`, `agent`, and `system`. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) to assign as the config owner. Mutually exclusive with `team`, `agent`, and `system`. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable path that uniquely identifies the config within its owner scope, e.g. `"my-agent/v1"`. Must be unique within the app + org + owner combination. + pub virtual_path: Option, +} + +/// Encrypts a plaintext secret and returns a ciphertext string safe for +/// embedding directly in config content using the `secret_value!` interpolation +/// syntax. The ciphertext is bound to the app's (or org's) key-encryption key +/// (KEK) so it can only be decrypted at runtime within the same scope. +/// +/// When `org` is provided, the KEK for that org is used; otherwise the +/// viewer's own org KEK is used, falling back to the app-level KEK for viewers +/// with no org context. +/// +/// The plaintext is never stored. Requires app scope. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ConfigEncryptSecretInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) whose KEK to use for encryption. Overrides the viewer's own org. Omit to use the viewer's org KEK, or the app-level KEK when the viewer has no org context. + pub org: Option, + /// The secret value to encrypt. Never stored; only the resulting ciphertext is returned. + pub plaintext: String, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ConfigEncryptSecretResponse { + /// Encrypted ciphertext string. Embed this in config content using the `secret_value!` interpolation syntax to have it decrypted at runtime. + pub encrypted_value: String, +} + +/// Query parameters for get_api_v1_config_facets. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigFacetsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// App ID (`app_...`). Present when mounted under the developer scope; injected automatically. + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) to scope facets to that team's configs. Mutually exclusive with `user`. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) to scope facets to that user's configs. Defaults to the current user when the viewer is a user and no selector is provided. Mutually exclusive with `team`. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to narrow facets to configs belonging to that org. + pub org: Option, +} + +/// Validates raw config content against the schema for a given config kind +/// without saving anything. Returns a structured result indicating whether the +/// content is valid and, if not, a list of error messages. +/// +/// Use this endpoint to give users early feedback before calling create or +/// update. The owner context is used for any kind-specific validation rules that +/// are owner-aware; provide the same owner you intend to use on the write call. +/// +/// Requires app scope. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ConfigValidateInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) that would own the config. Used for owner-aware validation rules. Mutually exclusive with `team` and `user`. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional metadata used by kind-specific validation. File and Image configs require `data.name` when validating direct binary content. + pub data: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Encoding of `raw_content`. Omit or set `"raw"` for literal content; set `"base64"` when sending binary content such as images or PDFs in JSON. + pub data_encoding: Option, + /// Config kind whose schema the content is validated against, e.g. `"Agent"` or `"APITool"`. + pub kind: String, + /// MIME type of `raw_content`, e.g. `"application/x-yaml"` or `"application/json"`. Used to parse the content before validation. + pub mime_type: String, + /// Raw content bytes to validate. Parsed according to `mime_type` before schema validation. + pub raw_content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) that would own the config. Used for owner-aware validation rules. Mutually exclusive with `user` and `agent`. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) that would own the config. Used for owner-aware validation rules. Mutually exclusive with `team` and `agent`. + pub user: Option, +} + +/// Query parameters for get_api_v1_config__config. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigConfigParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Set `true` to resolve a system-owned config by `virtual_path` or `lookup_key`. Requires a privileged viewer (developer or all-powerful) or an org admin. + pub system: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to narrow the lookup to configs belonging to that org. + pub org: Option, +} + +/// Updates an existing config. When `raw_content` is provided, a new version is +/// created and becomes the current version. When `raw_content` is omitted, only +/// metadata fields (`virtual_path`, `lookup_key`, `relative_path`, +/// `parent_solution`) are updated without creating a new version. +/// +/// Use `expected_version` for optimistic concurrency control: if the config's +/// current version number does not match the supplied value the request returns +/// 409. This prevents overwriting concurrent edits. +/// +/// The config may be addressed by its ID (`cfg_...`), `virtual_path`, or +/// `lookup_key`. When addressing by `lookup_key` or `virtual_path`, you must +/// supply exactly one owner selector (`team`, `user`, `agent`, or `system`). +/// Both `not_found` and `forbidden` outcomes are surfaced as 404. +/// +/// Requires app scope. The viewer must have modify rights on the config. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1ConfigConfigInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of this update, stored on the new version record. + pub change_description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to store on the new version alongside the content. + pub data: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Encoding of `raw_content`. Omit or set `"raw"` for literal content; set `"base64"` when sending binary content such as images or PDFs in JSON. + pub data_encoding: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Version number the caller expects to be current. If the config's actual current version does not match, the request returns 409 to signal a concurrent modification. Omit to skip optimistic locking. + pub expected_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New `lookup_key` for the config. Updates the key without creating a new version when `raw_content` is omitted. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of `raw_content`, e.g. `"application/x-yaml"` or `"application/json"`. Defaults to the existing MIME type when `raw_content` is provided without this field. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to narrow the lookup to configs belonging to that org. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Solution config ID (`cfg_...`) to set as the config's parent solution provenance. Clears the value when set to an empty string. + pub parent_solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New raw content bytes for the config. When provided, a new version is created. Omit to perform a metadata-only update without incrementing the version. + pub raw_content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated path of this config within its parent bundle. Only meaningful when the config has a `parent`. + pub relative_path: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Set `true` to resolve a system-owned config by `virtual_path` or `lookup_key`. Requires a privileged viewer (developer or all-powerful) or an org admin. + pub system: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New `virtual_path` for the config. Updates the path without creating a new version when `raw_content` is omitted. + pub virtual_path: Option, +} + +/// Soft-deletes a config by marking it as archived. Archived configs are hidden +/// from list and show endpoints but are not permanently removed; use the +/// unarchive endpoint to restore one, or the delete endpoint for permanent +/// removal. +/// +/// The config may be addressed by its ID (`cfg_...`), `virtual_path`, or +/// `lookup_key`. When addressing by `lookup_key` or `virtual_path`, you must +/// supply exactly one owner selector (`team`, `user`, `agent`, or `system`); +/// passing an owner selector when addressing by ID returns 422. +/// +/// Requires app scope. The viewer must have modify rights on the config. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ConfigConfigArchiveInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to narrow the lookup to configs belonging to that org. Useful when the viewer has access to multiple orgs. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Set `true` to resolve a system-owned config by `virtual_path` or `lookup_key`. Requires a privileged viewer (developer or all-powerful) or an org admin. + pub system: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub user: Option, +} + +/// Transfers a config to a new owner (`team`, `user`, `agent`, or `system`). +/// Exactly one of the new-owner selectors must be provided. The config must be +/// addressed by its ID (`cfg_...` or UUID); `virtual_path` and `lookup_key` +/// are not accepted to avoid ambiguity — look up the ID first if needed. +/// +/// For non-system targets the new owner's org is derived automatically from the +/// target entity; supplying `org` in that case returns 422. For `system:true` +/// targets, `org` controls the resulting org scope: omit to keep the existing +/// `org_id`, supply a value to set a specific org, or pass `null`/blank to make +/// the config app-level (operator viewers only). +/// +/// Operator viewers (developer credentials or all-powerful viewers) may transfer +/// to any owner. All other viewers are restricted to owners they can themselves +/// access (team membership, user identity, agent scope, or `system` with the +/// appropriate privilege). +/// +/// Requires app scope. The viewer must have modify rights on the config. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ConfigConfigChangeOwnerInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New owner: Agent ID (`agt_...`). Mutually exclusive with `team`, `user`, and `system`. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Only valid when `system:true`. Omit to keep the config's existing `org_id`; supply an org ID (`org_...`) to set a specific org scope; pass blank or `null` to make the config app-level (operator viewers only). Setting `org` for `team`, `user`, or `agent` targets returns 422. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Set `true` to transfer to system ownership (app-level or org-scoped). Requires a privileged viewer. Mutually exclusive with `team`, `user`, and `agent`. + pub system: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New owner: Team ID (`team_...`). Mutually exclusive with `user`, `agent`, and `system`. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New owner: User ID (`usr_...`). Mutually exclusive with `team`, `agent`, and `system`. + pub user: Option, +} + +/// Query parameters for get_api_v1_config__config_content. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigConfigContentParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Set `true` to resolve a system-owned config by `virtual_path` or `lookup_key`. Requires a privileged viewer (developer or all-powerful) or an org admin. + pub system: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to narrow the lookup to configs belonging to that org. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Output format for content conversion. One of `"yaml"` or `"json"`. Omit to return the content in its stored format. Returns 400 if conversion is not possible. + pub format: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether to inject platform-managed protected fields (such as `virtual_path`) into the returned content. Defaults to `true`. Set to `false` to receive the raw stored bytes. + pub inject_protected_fields: Option, +} + +/// Restores a previously archived config, making it visible again in list and +/// show responses. The config's content and version history are unchanged. +/// +/// The config may be addressed by its ID (`cfg_...`), `virtual_path`, or +/// `lookup_key`. When addressing by `lookup_key` or `virtual_path`, you must +/// supply exactly one owner selector (`team`, `user`, `agent`, or `system`); +/// passing an owner selector when addressing by ID returns 422. +/// +/// Requires app scope. The viewer must have modify rights on the config. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ConfigConfigUnarchiveInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to narrow the lookup to configs belonging to that org. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Set `true` to resolve a system-owned config by `virtual_path` or `lookup_key`. Requires a privileged viewer (developer or all-powerful) or an org admin. + pub system: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub user: Option, +} + +/// Query parameters for get_api_v1_config__config_versions. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigConfigVersionsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) to use as the owner when resolving by `virtual_path` or `lookup_key`. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Set `true` to resolve a system-owned config by `virtual_path` or `lookup_key`. Requires a privileged viewer (developer or all-powerful) or an org admin. + pub system: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to narrow the lookup to configs belonging to that org. + pub org: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigConfigVersionsResponseVersionsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable summary of what changed in this version, as provided by the author. `null` if no description was supplied. + pub change_description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// SHA-256 digest of the raw config content encoded as `sha256:`. Uses the same algorithm as the CLI `computeContentHash` helper. `null` for versions created before this field was introduced. + pub content_hash: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this config version was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary structured metadata stored alongside this version. `null` when no extra data was provided. + pub data: Option>, + /// Config version ID (`cfv_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) that owns this config version. `null` for personal configs. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sandbox ID (`sbx_...`) this version was saved under. `null` for production configs. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config version ID (`cfv_...`) for the Solution version this config version was installed from. `null` for standalone configs and legacy rows. + pub source_solution_config_version: Option, + /// Monotonically increasing integer identifying this version within the config. Starts at 1. + pub version_number: i64, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigConfigVersionsResponse { + /// Array of version objects ordered from most recent to oldest. + pub versions: Vec, +} + +/// Query parameters for get_api_v1_config_kinds. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigKindsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// One or more config kind names to include in the response (e.g., `"Agent"`, `"APITool"`). Omit to return all non-private kinds. + pub kind: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigKindsResponseDataItem { + /// Structural role of this kind. `"root"` kinds are standalone configs; `"supplemental"` kinds extend or augment a root config. + pub classification: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Markdown prose describing what this config kind represents and how to use it. `null` when no description has been registered for this kind. + pub description: Option, + /// The config kind identifier (e.g., `"Agent"`, `"APITool"`). Used as the `kind` value when creating or filtering configs. + pub kind: String, + /// `true` when a sample YAML document is available for this kind via the schema endpoint. + pub sample_available: bool, + /// `true` when a JSON Schema definition is available for this kind via the schema endpoint. + pub schema_available: bool, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigKindsResponse { + /// Array of config kind objects, sorted alphabetically by `kind` name. + pub data: Vec, +} + +/// Query parameters for get_api_v1_config_system. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigSystemParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to a single config kind, e.g. `"Agent"` or `"APITool"`. Use `kinds` to filter by multiple kinds at once. + pub kind: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to configs whose `kind` is in this list. When both `kind` and `kinds` are provided, `kinds` takes precedence. + pub kinds: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Exclude configs whose `virtual_path` starts with any of the listed string prefixes. + pub excluded_path_prefixes: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to retrieve, 1-indexed. Defaults to `1`. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of results per page. Defaults to `50`; maximum is `200`. Values above the maximum are clamped to `200`. + pub page_size: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigSystemResponseDataItemCurrentVersion { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable summary of what changed in this version, as provided by the author. `null` if no description was supplied. + pub change_description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// SHA-256 digest of the raw config content encoded as `sha256:`. Uses the same algorithm as the CLI `computeContentHash` helper. `null` for versions created before this field was introduced. + pub content_hash: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this config version was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary structured metadata stored alongside this version. `null` when no extra data was provided. + pub data: Option>, + /// Config version ID (`cfv_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) that owns this config version. `null` for personal configs. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sandbox ID (`sbx_...`) this version was saved under. `null` for production configs. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config version ID (`cfv_...`) for the Solution version this config version was installed from. `null` for standalone configs and legacy rows. + pub source_solution_config_version: Option, + /// Monotonically increasing integer identifying this version within the config. Starts at 1. + pub version_number: i64, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigSystemResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) associated with this config. `null` if not linked to an agent. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this config was first created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The most recently saved version of this config. `null` if the config has never been saved with content. + pub current_version: Option, + /// Config ID (`cfg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this config has been archived. Archived configs are hidden from default listings but remain accessible by ID. + pub is_archived: Option, + /// Type of config, e.g. `"Agent"` or `"APITool"`. Determines which fields and validation rules apply. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable, user-defined key used to look up this config without knowing its ID. `null` if not set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the config's content, e.g. `"text/yaml"`. `null` if not determined. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) this config belongs to. `null` for configs not scoped to an org. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Parent bundle config ID (`cfg_...`). Present only for configs that are children of a bundle; `null` otherwise. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID (`cfg_...`) of the solution config this config was imported with. `null` if the config was not imported via a solution. + pub parent_solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Raw file content as a string. Populated only for system configs; `null` for user-owned configs. + pub raw_content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Path of this config relative to its parent bundle root. Present only for bundle children; `null` otherwise. + pub relative_path: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sandbox identifier this config belongs to. `null` for production configs. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`tea_...`) that owns this config. `null` for personal (user-scoped) configs. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this config was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) who owns this config. `null` for team-scoped configs. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Logical path uniquely identifying this config within its team, e.g. `"agents/my-agent.yaml"`. `null` for configs without an explicit path. + pub virtual_path: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ConfigSystemResponse { + /// Array of system config objects for the current page. + pub data: Vec, + /// `true` when a subsequent page of results exists. + pub has_next: bool, + /// `true` when a previous page of results exists. + pub has_prev: bool, + /// The current page number (1-indexed). + pub page: i64, + /// Number of results returned per page. + pub page_size: i64, + /// Total number of system configs matching the applied filters across all pages. + pub total_entries: i64, + /// Total number of pages given the current `page_size`. + pub total_pages: i64, +} + +/// Creates a copy of a system (template) config and transfers ownership to a team +/// or user. All dependencies bundled with the source config are cloned alongside it. +/// Responds with HTTP 201 and the newly created config on success. +/// +/// You must specify exactly one destination owner via `team` or `user`. Callers +/// authenticated as an app (developer portal) may omit the owner — the clone is +/// then scoped to the system owner automatically. +/// +/// Use `virtual_path` and `lookup_key` to override the corresponding fields on the +/// clone; omitting them carries the values from the source. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ConfigSystemSystemCloneInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Override the `lookup_key` on the cloned config. When omitted, the source value is used. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to scope the clone to. When set, must match the authenticated viewer's org. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`tea_...`) that will own the cloned config. Required unless `user` is provided or the caller is app-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) that will own the cloned config. Required unless `team` is provided or the caller is app-scoped. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Override the `virtual_path` on the cloned config. When omitted, the source value is used. + pub virtual_path: Option, +} + +/// Query parameters for get_api_v1_custom_objects. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1CustomObjectsParams { + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Schema type identifier (`lookup_key`) to filter by. Only objects of this type are returned. Alias of `schema_key`; either name is accepted. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Legacy alias for `type`. Prefer `type` on new clients. When both are supplied, `type` wins. + pub schema_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Exact `row_key` value to match. When supplied, only objects with this partition key are returned. + pub row_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// One or more `sort_key` values to match within the `row_key` partition. Requires `row_key` to be set. + pub sort_key: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// One or more team IDs (`team_...`) to filter by owning team. Returns objects owned by any of the supplied teams. + pub team: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// One or more user IDs (`user_...`) to filter by owning user. Returns objects owned by any of the supplied users. + pub user: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// One or more agent IDs to filter by owning agent. Returns objects owned by any of the supplied agents. + pub agent: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// One or more organization IDs (`org_...`) to filter by. Typically used by admins to query system-owned objects in a specific org. + pub org: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full-text search string matched against the schema's configured search fields. When supplied, results are ordered by relevance score descending instead of creation time descending. + pub query: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Case-insensitive substring search applied across the schema type and serialized field values. Deprecated — prefer `query` for full-text search. Retained for developer-namespace clients. + pub search: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to retrieve (1-indexed). Defaults to `1`. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of objects per page. Defaults to `25`; maximum is `100`. + pub page_size: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1CustomObjectsInputAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1CustomObjectsInputAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1CustomObjectsInputAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1CustomObjectsInputAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Creates a new custom object of the given schema type and returns the +/// persisted object. The caller must be authenticated and authorized to create +/// objects of the specified type. +/// +/// Identify the schema with `type` (preferred), or the legacy aliases +/// `schema_key` (lookup key) / `config` (config ID). Exactly one identifier is +/// required; when more than one is supplied, `type` wins over `schema_key`, +/// which wins over `config`. +/// +/// Owner resolution follows a priority order: if `team` is supplied the object +/// is team-owned; if `user` is supplied it is owned by that user; if `agent` is +/// supplied it is agent-owned; otherwise the object is owned by the authenticated +/// user. Pass `system: true` explicitly to force system ownership — this requires +/// elevated API credentials and returns 403 if the caller lacks permission. +/// +/// If the schema declares a `row_key` (and optionally a `sort_key`), you may +/// pass `upsert: true` to update an existing object at that key instead of +/// receiving a 409 Conflict. The response status is `200` on an update and +/// `201` on a new create. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1CustomObjectsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for the custom object. Supports explicit `read` and `write` grants to users, teams, organizations, organization roles, agents, or everyone. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent user ID to set as the object owner. Used when neither `team` nor `user` is supplied. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config ID (`cfg_...`) that resolves to the target schema. Provide one of `type`, `schema_key`, or `config`. + pub config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of field values for the new object. Must conform to the schema's field definitions. Omit to create an object with all fields at their default or null values. + pub fields: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to associate with the object. Typically required for system-owned objects. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Legacy alias for `type` (schema `lookup_key`). Prefer `type` on new clients. Provide one of `type`, `schema_key`, or `config`. + pub schema_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, creates a system-owned object with no team, user, or agent owner. Requires elevated API credentials; returns 403 if the caller lacks permission. + pub system: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) to set as the object owner. When supplied, takes priority over `user` and `agent`. + pub team: Option, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Schema type identifier (`lookup_key`) that defines the object's shape and validation rules. Preferred over the legacy `schema_key` / `config` aliases. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true` and the schema declares a `row_key`, updates the existing object at that key for the same owner instead of returning 409 Conflict. Returns HTTP 200 on update and 201 on create. + pub upsert: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`user_...`) to set as the object owner. Used when neither `team` nor a higher-priority owner is set. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct DeleteApiV1CustomObjectsObjectResponse { + /// Always `true` when the deletion succeeds. + pub deleted: bool, + /// ID of the deleted custom object (`cobj_...`). + pub id: String, +} + +/// Query parameters for get_api_v1_custom_objects__object. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1CustomObjectsObjectParams { + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Schema type identifier (`lookup_key`) of the object. Optional; used for routing context only. + pub type_: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1CustomObjectsObjectInputAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1CustomObjectsObjectInputAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1CustomObjectsObjectInputAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1CustomObjectsObjectInputAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Updates the fields of an existing custom object and returns the updated +/// object along with its new version number. The authenticated viewer must have +/// permission to modify the object. +/// +/// You may supply `fields` (a full or partial key-value map to merge into the +/// object), `field_ops` (granular array operations per field), `acl`, or any +/// compatible combination. The same field name must not appear in both +/// `fields` and `field_ops`, which returns 422. Returns 404 if the object does +/// not exist or has been deleted. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1CustomObjectsObjectInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated access control list. Supports full replacement via `grants` or targeted `add`/`remove` operations. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Granular array operations to apply per field (e.g. append, prepend, remove). A field must not appear in both `fields` and `field_ops`. + pub field_ops: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of field values to merge into the object. Only the supplied keys are affected. + pub fields: Option>, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Schema type identifier (`lookup_key`) of the object. Optional; used for routing context only. + pub type_: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1CustomObjectsObjectResponseDataAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1CustomObjectsObjectResponseDataAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1CustomObjectsObjectResponseDataAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1CustomObjectsObjectResponseDataAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1CustomObjectsObjectResponseData { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list governing read and write access to this custom object. Only returned to resource owners and privileged or organization-admin viewers; `null` for everyone else. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the custom object was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Map of field names to their current values as defined by the object's schema type. + pub fields: Option>, + /// Unique identifier for the custom object (`cobj_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this object belongs to (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// An optional stable key used to identify this object by a caller-controlled string rather than its generated ID. `null` if not set. + pub row_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment this object is scoped to (`dsb_...`). `null` for production objects. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The lookup key of the schema type that defines this object's field structure. `null` if the schema type has not been set. + pub schema_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this object (`tem_...`). `null` if the object is not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the custom object was last modified (ISO 8601). `null` if the object has never been updated after creation. + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this object (`usr_...`). `null` if the object is not user-scoped. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optimistic concurrency version of the object. Increments with each successful update; pass this value in write operations to detect conflicting changes. + pub version: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1CustomObjectsObjectResponse { + /// The custom object after the update has been applied. + pub data: PutApiV1CustomObjectsObjectResponseData, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Version metadata for the updated object. + pub meta: Option>, +} + +/// Contract-defined values for PostApiV1ExtractionsInputDestinationKind. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum PostApiV1ExtractionsInputDestinationKind { + /// The config wire value. + #[serde(rename = "config")] + Config, + /// The storage wire value. + #[serde(rename = "storage")] + Storage, +} + +/// Contract-defined values for PostApiV1ExtractionsInputMode. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum PostApiV1ExtractionsInputMode { + /// The link wire value. + #[serde(rename = "link")] + Link, + /// The site wire value. + #[serde(rename = "site")] + Site, +} + +/// Records a text-extraction job for a document (`file`) or a URL (`url` + `mode`). +/// The job is owner-scoped and tagged with the caller-supplied `destination` +/// namespace, **without** committing knowledge to an agent (no embeddings, no +/// agent attach). +/// +/// Exactly one of `file` or (`url` + `mode`) is required. +/// +/// Document extraction (`file`) runs synchronously: the response already +/// reflects the final state (`done` with its output, or an error if extraction +/// couldn't complete), status `201`. URL extraction (`url` + `mode`) submits an +/// async crawl and returns immediately with state `running`, status `202` — +/// poll `GET /extractions/:extraction` for its terminal state. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ExtractionsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Owning agent (`agt_...`) — scopes the extraction and its outputs. + pub agent: Option, + /// Where outputs are written. + pub destination_kind: PostApiV1ExtractionsInputDestinationKind, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Destination virtual_path prefix. Required for `destination_kind=config`, where it must name at least one path segment (`.` and `..` segments are dropped). + pub destination_path: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Source file id (`fil_...`) for document extraction. Runs synchronously, so the source must be at most 10MB; larger files are rejected. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Crawl cap for `mode=site` — must be at least 1 (defaults to 100; `link` is always 1). + pub max_pages: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Required with `url`. Document extraction is selected by `file` instead and takes no `mode` (its `kind` is `document`). + pub mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Owning organization (`org_...`). Defaults to the viewer's org. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Source URL for link/site extraction. + pub url: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1FilesInputAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1FilesInputAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1FilesInputAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1FilesInputAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Creates a new file from base64-encoded content and returns the resulting file object, +/// including a signed download URL. Use this endpoint to store images, documents, or +/// other binary assets that can then be referenced by agents, teams, or users. +/// +/// App scope is derived from the authenticated viewer's bearer token or publishable key. +/// You may optionally associate the file with an organization, team, user, or agent by +/// passing the corresponding ID. If no owner is specified and the viewer is a user, the +/// file is automatically attributed to that user. +/// +/// Pass `share: true` to additionally mint a stable public URL for the file +/// (returned as `share_url`), fetchable by anyone without authentication — for +/// example to embed an uploaded image in a GitHub PR body or other external +/// markdown. The URL does not expire. Sharing is revoked by setting +/// `share: false` on `PATCH /api/v1/files/:file` with the same credential +/// (or `archastro update file --unshare`); re-enabling sharing +/// reactivates previously issued URLs. Only image content types can be +/// shared. +/// +/// Returns `422` when the `data` field is not valid base64, the changeset is +/// invalid, or `share` is requested for a non-image content type. +/// Returns `403` when the request lacks the required app scope. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1FilesInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for the file. Supports explicit `read` and `write` grants to users, teams, organizations, organization roles, agents, or everyone. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agi_...`) to associate with this file. When provided, the file's organization is derived from the agent. + pub agent: Option, + /// MIME type of the file, e.g. `"image/png"` or `"application/pdf"`. + pub content_type: String, + /// Base64-encoded binary content of the file to upload. + pub data: String, + /// Original filename including extension, e.g. `"avatar.png"`. + pub filename: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to associate with this file. Optional; defaults to the viewer's organization when omitted. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, marks the file publicly shareable and returns a stable, non-expiring `share_url` fetchable without authentication. Only image content types can be shared. + pub share: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`tem_...`) that owns this file. Takes precedence over `user` when both are provided. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) that owns this file. Defaults to the authenticated user when neither `user` nor `team` is specified. + pub user: Option, +} + +/// Updates mutable fields of an existing file. Only the fields you supply are +/// changed; omitted fields retain their current values. The file's stored content +/// and `content_type` cannot be changed after creation. +/// +/// This endpoint is the companion to `share: true` on file upload: the same +/// credential that granted public sharing can revoke it here with `share: false` +/// (or grant it later with `share: true`; only image content types can be +/// shared, and re-enabling sharing reactivates any previously issued share +/// URLs). App scope is derived from the authenticated viewer, matching upload. +/// +/// A file that exists but is not visible to the current viewer returns `404` +/// rather than `403` to avoid revealing the file's existence. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1FilesFileInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New name for the file, including extension, e.g. `"report_v2.pdf"`. Omit to leave the current filename unchanged. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of provider-specific metadata to store alongside the file. Replaces the entire existing `provider_metadata` map. Omit to leave it unchanged. + pub provider_metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Set `true` to mark the file publicly shareable via its stable `share_url` (image content types only), or `false` to revoke public sharing. Re-enabling sharing reactivates any previously issued share URLs for the file. Omit to leave sharing unchanged. + pub share: Option, +} + +/// Query parameters for get_api_v1_files__file_avatar. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1FilesFileAvatarParams { + /// HMAC capability token authorizing access to this specific file. Obtained from the avatar URL minted when the profile picture was set. + pub token: String, +} + +/// Query parameters for get_api_v1_files__file_org_logo. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1FilesFileOrgLogoParams { + /// HMAC capability token authorizing access to this specific file. Obtained from the `org_logo.url` minted when the logo was serialized. + pub token: String, +} + +/// Query parameters for get_api_v1_files__file_share. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1FilesFileShareParams { + /// HMAC capability token authorizing access to this specific file. Obtained from the `share_url` returned when the file was uploaded with `share: true`. + pub token: String, +} + +/// Accepts an invite on behalf of the authenticated user and adds them to the +/// associated team or thread. The invite `key` is passed in the request body +/// rather than the URL so it never appears in access logs, `Referer` headers, +/// or error-reporter URL captures. +/// +/// This endpoint requires an authenticated end-user session. S2S secret-key +/// tokens and unauthenticated requests are rejected with `401`. If the +/// authenticated user is already a member of the invite's target, the request +/// returns `409`. Both per-IP and per-user rate limits apply; exceeding either +/// returns `429`. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1InvitesAcceptInput { + /// Opaque invite key identifying the invite to accept. Obtained from an invite link or a previous invite creation response. + pub key: String, +} + +/// Query parameters for get_api_v1_knowledge_documents. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1KnowledgeDocumentsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to return. Defaults to 1. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of documents per page. Defaults to 25. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Case-insensitive prefix filter applied to the document title. + pub q: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only documents belonging to these source IDs (`cso_...`). Multiple values are OR'd. + pub source: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only documents belonging to these installation IDs. Multiple values are OR'd. + pub installation: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only documents owned by these agent IDs. Multiple values are OR'd. + pub agent: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1KnowledgeDocumentsResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this document (`agi_...`). `null` if owned by a user or team. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lowercase-hex sha256 of the document's full text, covering content only — not `title` or `metadata`. Compare it against a hash of your local copy to decide whether the document needs re-ingesting, without fetching `/content`. `null` for documents ingested before this field existed; it is not backfilled. + pub content_hash: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the document was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the backing storage file (`fil_...`) when the document is file-backed. `null` for inline documents. + pub file: Option, + /// Context document ID (`cdo_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the document. Shape varies by source type. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the context source this document belongs to (`cso_...`). + pub source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this document (`tem_...`). `null` if owned by a user or agent. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display title of the document. `null` if no title has been set. + pub title: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of lines in the document's text content. `0` if the document has no content. + pub total_lines: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total byte size of the document's text content. `0` if the document has no content. + pub total_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the document was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this document (`usr_...`). `null` if owned by a team or agent. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1KnowledgeDocumentsResponse { + /// Array of context document objects for the current page. + pub data: Vec, + /// `true` if a subsequent page exists; `false` when this is the last page. + pub has_next: bool, + /// `true` if a previous page exists; `false` when this is the first page. + pub has_prev: bool, + /// The current page number. + pub page: i64, + /// Maximum number of documents returned per page. + pub page_size: i64, + /// Total number of documents matching the applied filters across all pages. + pub total_entries: i64, + /// Total number of pages given the current `page_size`. + pub total_pages: i64, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1KnowledgeDocumentsDocumentInputContent { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the replacement content, such as `"text/plain"`. + pub content_type: Option, + /// The replacement document bytes. + pub data: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Encoding of `data`: `"raw"` (default) or `"base64"`. + pub data_encoding: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename for the replacement content. + pub filename: Option, +} + +/// Replaces one document's content while preserving its document ID. The update +/// runs asynchronously through the document's source pipeline: bytes are +/// extracted and chunked, the prior chunks are replaced atomically, and fresh +/// document and chunk embeddings are queued. +/// +/// Supply exactly one of `file` or `content`. Omitted `title` and `metadata` +/// retain their current values. The response is an ingestion that can be polled +/// at `GET /api/v1/knowledge_ingestions/:id` until it reaches `succeeded` or +/// `failed`. `succeeded` means the replacement content and full-text indexes are +/// committed and the embedding refresh is durably queued; vector computation +/// continues in the retryable embedding worker. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1KnowledgeDocumentsDocumentInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Inline replacement bytes. Mutually exclusive with `file`. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of an already-uploaded file (`fil_...`). Mutually exclusive with `content`. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement metadata map. Omit to retain the current metadata. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement display title. Omit to retain the current title. + pub title: Option, +} + +/// Query parameters for get_api_v1_knowledge_documents__document_content. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1KnowledgeDocumentsDocumentContentParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Starting position for a content slice. When `unit` is `"lines"`, this is a 1-indexed line number. When `unit` is `"bytes"`, this is a 0-indexed byte offset. Omit to return the full document. + pub offset: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of units to return when slicing. Defaults to 200 when `unit` is `"lines"` and 8192 when `unit` is `"bytes"`. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Unit to use for `offset` and `limit`. One of `"lines"` (default) or `"bytes"`. + pub unit: Option, +} + +/// Contract-defined values for GetApiV1KnowledgeSourcesParamsOwnerScope. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1KnowledgeSourcesParamsOwnerScope { + /// The any wire value. + #[serde(rename = "any")] + Any, + /// The individual wire value. + #[serde(rename = "individual")] + Individual, + /// The system wire value. + #[serde(rename = "system")] + System, +} + +/// Query parameters for get_api_v1_knowledge_sources. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1KnowledgeSourcesParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to retrieve. Defaults to 1. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of knowledge sources to return per page. Defaults to 25. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter sources whose type contains this string. Case-insensitive substring match. + pub search: Option, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Exact knowledge source type to filter by, e.g. `"knowledge/documents"`. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Installation ID (`ins_...`). Returns only sources associated with this installation. + pub installation: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`). Returns only sources owned by or associated with this agent. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`). Returns only sources belonging to this organization. Combine with `owner_scope: "system"` to retrieve org-level system sources. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter by ownership scope. One of `"any"` (default — returns all visible sources), `"individual"` (only sources owned by a user, team, or agent), or `"system"` (only sources with no individual owner, typically org-level). + pub owner_scope: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1KnowledgeSourcesResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this source (`agt_...`). `null` if owned by a human user or team. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the context installation that provisioned this source (`cin_...`). `null` when the source was created directly rather than through an installation. + pub context_installation: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this knowledge source was created (ISO 8601). + pub created_at: Option>, + /// Knowledge source ID (`cso_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to this source. Useful for storing caller-defined labels or references. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this source belongs to (`org_...`). `null` if not scoped to an org. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent knowledge source (`cso_...`) when this source was derived from another. `null` for top-level sources. + pub parent_source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Type-specific configuration object. The keys depend on the source `type`; see the create endpoint for the expected shape per type. + pub payload: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this source is scoped to (`sbx_...`). `null` outside sandbox contexts. + pub sandbox: Option, + /// Current lifecycle state of the source. One of `"active"` (ingestion running normally) or `"paused"` (ingestion suspended). + pub state: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this source (`tea_...`). `null` if owned by a user, agent, or org. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the chat thread this source is associated with (`thr_...`). `null` when not thread-scoped. + pub thread: Option, + #[serde(rename = "type")] + /// Source type identifier (e.g. `"gmail"`, `"github_activity"`). Determines the shape of `payload` and the ingestion behavior. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this knowledge source was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this source (`usr_...`). `null` if owned by a team, agent, or org. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1KnowledgeSourcesResponse { + /// Array of knowledge source objects for the current page. + pub data: Vec, + /// `true` if a subsequent page exists, `false` if this is the last page. + pub has_next: bool, + /// `true` if a previous page exists, `false` if this is the first page. + pub has_prev: bool, + /// Current page number. + pub page: i64, + /// Number of results returned per page. + pub page_size: i64, + /// Total number of knowledge sources matching the query across all pages. + pub total_entries: i64, + /// Total number of pages available. + pub total_pages: i64, +} + +/// Creates a new knowledge source of the requested type and returns the created object. +/// +/// Only types listed by `GET /api/v1/knowledge_sources/kinds` may be created through this +/// endpoint. Other source types — such as `webhook/inbound`, `connectors/*/emails`, and +/// `thread/messages` — are provisioned automatically by server-driven flows (webhook +/// auto-provisioning, installation activation, connector lifecycle events) and cannot be +/// created directly via the API. +/// +/// Exactly one of `team`, `user`, `agent`, or `org` must identify the owner of the new +/// source. Omit `org` when an individual owner (`team`, `user`, or `agent`) is supplied; +/// include `org` alone for org-level system-owned sources. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1KnowledgeSourcesInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) that owns this source. Mutually exclusive with `team` and `user`. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to attach to the source. Returned as-is on reads. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`). Required for system-owned sources that have no individual owner (`team`, `user`, or `agent`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Parent knowledge source ID (`ksrc_...`). Use to create a child source. + pub parent_source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Type-specific configuration for the source. Shape depends on `type`. + pub payload: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Initial state of the source. One of `"active"` (default) or `"paused"`. Paused sources do not trigger ingestion automatically. + pub state: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) that owns this source. Mutually exclusive with `user` and `agent`. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Thread ID (`thr_...`) to associate this source with, if applicable. + pub thread: Option, + #[serde(rename = "type")] + /// Knowledge source type. Must be one of the values returned by `GET /api/v1/knowledge_sources/kinds`. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) that owns this source. Mutually exclusive with `team` and `agent`. + pub user: Option, +} + +/// Updates the mutable fields of an existing knowledge source and returns the updated +/// object. Only fields provided in the request body are changed; omitted fields retain +/// their current values. +/// +/// You can update the type-specific `payload`, the `metadata` map, and the `state`. To +/// pause a source and prevent automatic ingestion, set `state` to `"paused"`. To resume, +/// set it back to `"active"`. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1KnowledgeSourcesSourceInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to attach to the source. Replaces the entire existing `metadata` map when provided. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Type-specific configuration to replace on the source. Shape depends on the source `type`. Replaces the entire existing `payload` when provided. + pub payload: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Desired state of the source. One of `"active"` or `"paused"`. Paused sources do not trigger ingestion automatically. + pub state: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1KnowledgeSourcesSourceIngestInputContent { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the content, e.g. `"application/pdf"` or `"text/plain"`. + pub content_type: Option, + /// The raw document bytes. When `data_encoding` is `"base64"`, provide the base64-encoded representation of the binary content. + pub data: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Encoding format of `data`. One of `"raw"` (default, plain text) or `"base64"` (binary content such as images or PDFs, decoded server-side before storage). + pub data_encoding: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename for the document, e.g. `"report.pdf"`. + pub filename: Option, +} + +/// Starts an ingestion run on the specified knowledge source and returns the ingestion +/// object. Exactly one of two modes must be chosen per request: +/// +/// **Push mode** (`file` or `content`) — available for `knowledge/documents` sources only. +/// Supply the document bytes either as a reference to an already-uploaded file (`file`) or +/// as an inline blob (`content`). The runner stores the bytes and indexes the resulting +/// document. `title` and `metadata` are persisted on the document in push mode. +/// +/// **Pull mode** (`pull: true`) — re-triggers ingestion using the source's own configured +/// data. Use this to re-scrape a `scrape/site`, re-fetch a `web/link`, or re-process a +/// `file/document`. Not valid for `knowledge/documents` (which has no upstream — push new +/// bytes instead) or for source kinds populated by server-driven flows. `title` and +/// `metadata` are ignored in pull mode. +/// +/// If an ingestion is already active for the source, the existing ingestion is returned +/// rather than creating a duplicate. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1KnowledgeSourcesSourceIngestInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Inline document bytes to push to the source. Mutually exclusive with `file` and `pull`. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, reuse the source's existing document if the pushed content is byte-identical to it, instead of creating a duplicate. The reused document keeps its chunks and embeddings, and `title`/`metadata` from this request are still applied to it. Content that differs in any way always creates a new document. Defaults to `false`, which creates a new document on every push. Push mode only — not valid with `pull: true`. Check `metadata.document_reused` on the returned ingestion to see whether a document was actually reused. + pub dedupe: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of an already-uploaded file (`fil_...`). The runner reads filename and content type from the stored file. Upload the file via `POST /v1/files` first. Mutually exclusive with `content` and `pull`. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to attach to the ingested document. Applied in push mode only; ignored when `pull: true`. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, re-triggers ingestion using the source's own configured data. Re-scrapes a `scrape/site`, re-fetches a `web/link`, or re-processes a `file/document`. Mutually exclusive with `file` and `content`. Not valid for `knowledge/documents` sources. + pub pull: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display title for the ingested document. Applied in push mode only; ignored when `pull: true`. + pub title: Option, +} + +/// Query parameters for get_api_v1_kv. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1KvParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to retrieve. Applies to developer and server-to-server callers only. Defaults to 1. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of entries per page. Applies to developer and server-to-server callers only. Defaults to 25; maximum is 100. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to entries belonging to this user ID. Applies to developer and server-to-server callers only. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Substring match against user email address and full name. Applies to developer and server-to-server callers only. + pub user_search: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Prefix filter on the storage key. Returns only entries whose key starts with this string. Applies to developer and server-to-server callers only. + pub key: Option, +} + +/// Creates a new key-value storage entry for the target user under the given key. +/// The key must not already exist for this user; use the upsert endpoint to create +/// or overwrite in a single call. +/// +/// End-user (user-JWT) callers always write to their own storage. Developer and +/// server-to-server callers must supply a `user` param identifying the target user +/// within their app's scope. Attempting to write for a user in a different app +/// returns 404. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1KvInput { + /// Storage key for the entry. Must be a non-empty string unique to this user. + pub key: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Target user ID. Required when calling as a developer or with a server-to-server key; ignored for end-user callers. + pub user: Option, + /// Value to store under `key`. Must be a non-empty string. + pub value: String, +} + +/// Query parameters for get_api_v1_kv__key. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1KvKeyParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Target user ID. Required when calling as a developer or with a server-to-server key; ignored for end-user callers. + pub user: Option, +} + +/// Creates a new key-value storage entry for the given `key`, or overwrites the +/// value if an entry already exists. This is the idempotent alternative to the +/// create endpoint: safe to call regardless of whether the key already exists. +/// +/// End-user (user-JWT) callers always write to their own storage. Developer and +/// server-to-server callers must supply a `user` param identifying the target user +/// within their app's scope. Attempting to write for a user in a different app +/// returns 404. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1KvKeyInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Target user ID. Required when calling as a developer or with a server-to-server key; ignored for end-user callers. + pub user: Option, + /// New value to store under `key`. Must be a non-empty string. Replaces any existing value. + pub value: String, +} + +/// Creates or replaces the authenticated user's notification preference for a +/// given `(type, channel)` combination. This is an idempotent PUT: if no +/// preference exists for the composite key, a new row is created; if one +/// already exists, its `enabled` flag is updated to the value you provide. +/// +/// The recipient is derived from the authenticated viewer. You cannot set +/// preferences for another user through this endpoint. +/// +/// Pass `app_id` to scope the preference to a specific app's notifications — +/// most useful for the `app_*` notification type family. Omit `app_id` to +/// configure the system-level (no-app) slot. System-level and app-scoped +/// preferences are stored independently and do not overwrite each other. +/// +/// The `in_app` channel is not configurable and will be rejected with a +/// validation error if supplied. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1NotificationPreferencesInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// App to scope this preference to. Omit to configure the system-level (no-app) slot. App-scoped and system-level preferences are stored separately and do not affect each other. + pub app_id: Option, + /// Delivery channel to configure (e.g., `"email"`, `"sms"`). The `in_app` channel is not configurable and will be rejected with a validation error. + pub channel: String, + /// Whether the specified channel should be enabled for this notification type and scope. Set to `false` to suppress delivery on this channel. + pub enabled: bool, + #[serde(rename = "type")] + /// Notification type to configure. Use a builtin name (e.g., `"app_info"`, `"billing_alert"`) or a `"custom:"` identifier matching a NotificationType config registered in your app's bundle. Unknown type identifiers are rejected with a validation error. + pub type_: String, +} + +/// Query parameters for get_api_v1_notifications. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1NotificationsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter by notification status. One of `"all"`, `"active"`, `"unread"`, `"read"`, or `"archived"`. Defaults to `"all"` when omitted. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of notifications to return per page. Defaults to 20; maximum is 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor from a previous response's `after_cursor` field. Omit to fetch the most recent notifications. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1NotificationsResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the recipient archived this notification. `null` if the notification has not been archived. + pub archived_at: Option>, + /// When the notification was sent (ISO 8601). + pub created_at: chrono::DateTime, + /// Notification ID (`ntf_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the recipient marked this notification read. `null` if the notification has not been read. + pub read_at: Option>, + /// Type-specific render spec resolved at request time. All types include `title`, `kind`, and `actions`; custom types may add their own keys. Notifications whose type is no longer registered render with `kind: "unknown"`. + pub rendered: std::collections::BTreeMap, + /// Current read state of the notification. One of `"unread"`, `"read"`, or `"archived"`. + pub status: String, + #[serde(rename = "type")] + /// Notification type slug, e.g. `"app_info"` for a built-in type or `"custom:deploy_complete"` for a custom type. + pub type_: String, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1NotificationsResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass as `after_cursor` on the next request to fetch older notifications. `null` when this is the last page. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Always `null` — inbox pagination is forward-only and does not support fetching newer pages via cursor. + pub before_cursor: Option, + /// Array of notification objects for the current page, ordered newest first. + pub data: Vec, + /// `true` if additional (older) notifications exist beyond this page; `false` if this is the last page. + pub has_more: bool, +} + +/// Delivers a custom-typed notification to one of the calling app's users. +/// Apps define notification types by declaring `NotificationType` config objects +/// in their bundle (one per `lookup_key`). Supply the type as +/// `"custom:"` and provide a `data` map that is merged with +/// platform-provided context to render the notification's display fields. +/// +/// Only app-scoped tokens may call this endpoint — user tokens are rejected with +/// 403. The app scope is stamped onto the notification automatically; an app +/// cannot target recipients outside its tenant. Built-in platform types such as +/// `"app_info"` and `"billing_alert"` are not accepted here. +/// +/// Pass `idempotency_key` to deduplicate sends. If you call this endpoint twice +/// with the same `idempotency_key` for the same recipient, the second call +/// returns the original notification without creating a duplicate. The key is +/// scoped to the calling app, so the same raw key used by different apps cannot +/// collide. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1NotificationsSendInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value payload merged with platform-provided context (recipient, app, org, brand) when rendering the notification's display fields. Defaults to an empty object when omitted. + pub data: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional deduplication key. A second call with the same `idempotency_key` for the same recipient returns the originally-created notification without inserting a new record. Scoped per calling app. + pub idempotency_key: Option, + #[serde(rename = "type")] + /// Custom notification type identifier in the form `"custom:"`, where `` matches a `NotificationType` config declared in the calling app's bundle. + pub type_: String, + /// Recipient user ID (`usr_...`). Must be a member of the calling app's tenant. + pub user: String, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1NotificationsUnreadCountResponse { + /// Total number of notifications with `"unread"` status belonging to the authenticated user. + pub count: i64, +} + +/// Query parameters for get_api_v1_orgs. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1OrgsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Free-text search term matched against organization name, slug, and domain (case-insensitive). Omit to return all organizations in the app. + pub search: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to retrieve, starting at `1`. Defaults to `1` when omitted. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of organizations to return per page. Defaults to `25`; maximum is `100`. + pub page_size: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1OrgsResponseDataItem { + /// Primary domain associated with the organization, e.g. `"acme.com"`. + pub domain: String, + /// Organization ID (`org_...`). + pub id: String, + /// Display name of the organization. + pub name: String, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1OrgsResponse { + /// Array of organization objects for the current page. + pub data: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` when a subsequent page exists; `false` on the last page. + pub has_next: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` when a previous page exists; `false` on the first page. + pub has_prev: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The current page number returned. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The number of results per page used for this response. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of organizations matching the query across all pages. + pub total_entries: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of pages for the current query and page size. + pub total_pages: Option, +} + +/// Query parameters for get_api_v1_private_service_enrollments. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1PrivateServiceEnrollmentsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID or slug. Required for developer and server callers. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number. Defaults to 1. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Results per page. Defaults to 25; maximum is 100. + pub page_size: Option, +} + +/// Creates or safely replaces an unreserved one-time connector enrollment token. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1PrivateServiceEnrollmentsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID or slug. Required for developer and server callers. + pub org: Option, + /// Private service ID (`pvs_...`). + pub private_service: String, +} + +/// Query parameters for get_api_v1_private_service_enrollments__private_service_enrollment_id. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1PrivateServiceEnrollmentsPrivateServiceEnrollmentIdParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID or slug. Required for developer and server callers. + pub org: Option, +} + +/// Query parameters for get_api_v1_private_services. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1PrivateServicesParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID or slug. Required for developer and server callers. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number. Defaults to 1. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Results per page. Defaults to 25; maximum is 100. + pub page_size: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1PrivateServicesInputFunctionsItem { + /// Human-readable guidance describing when and why to call the operation. + pub description: String, + /// JSON Schema Draft 7 object describing the operation's argument object. + pub input_schema: std::collections::BTreeMap, + /// Stable operation name used when invoking the private service. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional JSON Schema Draft 7 object describing the successful result. + pub output_schema: Option>, +} + +/// Creates one immutable private service in the selected organization. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1PrivateServicesInput { + /// Complete callable contracts. Input schemas are required; output schemas are optional. + pub functions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID or slug. Required for developer and server callers. + pub org: Option, +} + +/// Query parameters for get_api_v1_private_services__private_service_id. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1PrivateServicesPrivateServiceIdParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID or slug. Required for developer and server callers. + pub org: Option, +} + +/// Creates a new sandbox for the caller's app. A sandbox is an isolated environment +/// that can hold its own set of API keys, allowing you to test integrations without +/// affecting production data. +/// +/// The caller must authenticate with app-scoped credentials. Org-scoped viewers +/// may create sandboxes for their organization; developers and all-powerful +/// callers may create app-level or org-scoped sandboxes. If `org` is supplied the +/// sandbox is scoped to that organization; otherwise it defaults to the +/// authenticated viewer's organization. +/// +/// Remote-eval sandboxes may set `purpose: "eval"` with `expires_at` at creation; +/// TTL is the sole cleanup mechanism for those sandboxes. Returns the new sandbox +/// with the auto-issued publishable key — use the create key endpoint to issue +/// secret keys. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SandboxesInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional eval sandbox expiry in ISO 8601 format. Must be paired with `purpose: "eval"`. + pub expires_at: Option>, + /// Human-readable display name for the sandbox. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to scope the sandbox to. Defaults to the authenticated viewer's organization when omitted. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional sandbox purpose marker. Only `"eval"` is accepted, and it must be paired with `expires_at`. + pub purpose: Option, + /// URL-safe identifier for the sandbox. Must be unique within the app. + pub slug: String, +} + +/// Issues a new API key for the specified sandbox. Keys can be either +/// `"publishable"` (safe to embed in client-side code) or `"secret"` (server-side +/// only). The full key value is returned once in the `full_key` field of this +/// response and is never retrievable again — store it securely immediately. +/// +/// The caller must authenticate with app-scoped credentials and be able to +/// modify the sandbox (org members for org sandboxes; developers / all-powerful +/// for app-level). If the sandbox does not belong to the caller's app or is not +/// visible, a 404 is returned. Multiple active keys per sandbox are supported; +/// revoke individual keys with the revoke key endpoint. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SandboxesSandboxKeysInput { + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key type. One of `"publishable"` or `"secret"`. Defaults to `"publishable"`. + pub type_: Option, +} + +/// Query parameters for get_api_v1_slack_channel_bindings. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1SlackChannelBindingsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only bindings whose Slack integration matches one of these integration IDs. Omit to return bindings across all integrations. + pub integration: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only bindings bound to one of these team IDs. Omit to return bindings for all teams. + pub team: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only bindings that have at least one of these agent user IDs attached. Omit to return bindings regardless of agent attachment. + pub agent: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only bindings that belong to one of these organization IDs. Omit to return bindings across all organizations visible to the caller. + pub org: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to retrieve, 1-indexed. Defaults to 1. Must be a positive integer. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of bindings to return per page. Defaults to 25; maximum is 100. + pub per_page: Option, +} + +/// Creates a new binding between a Slack channel and a team, or updates the +/// existing binding if one already exists for the given channel. The caller also +/// supplies a list of agents to attach to the binding and enroll as members of the +/// destination team. +/// +/// The caller must have team-manage rights on the destination team (and on the +/// currently bound team if the channel is being re-pointed). Returns 403 if +/// permission is insufficient. All write steps are idempotent, so retrying after +/// a partial failure is safe. +/// +/// On success the REST endpoint returns 201 Created. The script binding +/// (`slack.channel_bindings.upsert`) returns the full binding object including the +/// attached agents. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SlackChannelBindingsInput { + /// List of agent user IDs to attach to the binding and enroll as members of the destination team. Pass an empty array to bind the channel without attaching any agents. + pub agent_user_ids: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opt this channel into sustained bot-to-bot conversation: the reply loop brake is disabled for its mirror thread. Set when the counterparty is a known bot the agent should keep answering. Omitting the parameter leaves the stored value unchanged. + pub allow_bot_conversations: Option, + /// Slack channel ID to bind (e.g. `C01234ABCDE`). Acts as the natural key of the binding within the workspace. + pub channel_id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable label for the customer associated with this channel. Stored in the binding's config. `null` if omitted. + pub customer_label: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Cached value of Slack's `is_ext_shared` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. `null` if omitted. + pub is_ext_shared_cached: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Cached value of Slack's `is_private` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. Private channels are member-managed. `null` if omitted. + pub is_private_cached: Option, + /// Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. + pub slack_team_id: String, + /// ID of the team to bind the Slack channel to. The caller must have team-manage rights on this team. + pub team_id: String, +} + +/// Opens a Slack Connect channel with a new customer — creating one and sending +/// the invite, or adopting a shared channel you already have — and records who is +/// adding whom so the addition can finish once the customer accepts. +/// +/// The returned binding is **pending**: nothing mirrors, and no per-customer Team, +/// agent, or solution instance exists yet. Acceptance is asynchronous and may +/// never come. When it does, the addition completes in the background under the +/// identity of the admin who called this endpoint, re-checked live at that moment. +/// A caller who has since lost their admin role does not get a substitute — the +/// addition is refused and a human re-adds the customer. +/// +/// The caller must be an admin of the Slack integration's own organization. This +/// is the same authority the completion demands, checked here so a customer is +/// never invited into a channel whose addition can never finish. +/// +/// Deliberately not exposed as a script binding: this sends mail to a person +/// outside the org, so it stays a vendor-admin HTTP surface. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SlackChannelBindingsProvisionInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Name for a Slack channel to create for this customer. Required unless `existing_channel_id` is given. The channel is created private. + pub channel_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Address the Slack Connect invite is sent to. Required when creating a channel; optional when adopting one the customer is already in. Whoever accepts becomes the verified counterparty. + pub customer_email: Option, + /// The vendor's own primary key for this customer (`customer_id` / `account_id` / `tenant_id`). The per-customer agent's data access is locked to it. Immutable once the customer is added: re-targeting means offboarding and re-provisioning. + pub customer_key: String, + /// Human-readable name for the customer (e.g. `Acme, Inc.`). Used for the vendor's own dashboards and as the per-customer Team's name. Not an identity or an access control input. + pub customer_label: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Adopt this already-shared Slack Connect channel (e.g. `C01234ABCDE`) instead of creating one. Mutually exclusive with `channel_name`. + pub existing_channel_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// String-keyed values the per-customer solution instance is stamped with. Defaults to an empty map. + pub inputs: Option>, + /// Slack workspace team ID of the vendor's own Slack installation (e.g. `T01234ABCDE`). The customer's workspace is not known yet — it resolves from whoever accepts. + pub slack_team_id: String, + /// Config ID (`cfg_…`) of the org-installed Solution the per-customer instance is stamped from. Must be the organization's own installed copy, not the catalog original — instances stamped from a different config do not appear in the vendor's customer fleet. + pub template_config_id: String, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct DeleteApiV1SlackChannelBindingsChannelResponse { + /// Slack channel ID of the binding that was deleted. + pub channel: String, + /// Always `true` when the binding was successfully removed. + pub deleted: bool, +} + +/// Query parameters for get_api_v1_slack_channel_bindings__channel. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1SlackChannelBindingsChannelParams { + /// Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Used together with `channel` to uniquely identify the binding. + pub slack_team_id: String, +} + +/// Contract-defined values for GetApiV1SlackChannelBindingsChannelDeliveryOutcomesParamsOutcome. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1SlackChannelBindingsChannelDeliveryOutcomesParamsOutcome { + /// The delivered wire value. + #[serde(rename = "delivered")] + Delivered, + /// The floored wire value. + #[serde(rename = "floored")] + Floored, + /// The judge_refused wire value. + #[serde(rename = "judge_refused")] + JudgeRefused, + /// The failed wire value. + #[serde(rename = "failed")] + Failed, +} + +/// Query parameters for get_api_v1_slack_channel_bindings__channel_delivery_outcomes. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1SlackChannelBindingsChannelDeliveryOutcomesParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Only return attempts at or after this ISO 8601 timestamp (e.g. `2026-08-11T00:00:00Z`). Omit to return the most recent attempts regardless of age. + pub since: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only attempts with this outcome. Omit to return every outcome. Use `floored` and `judge_refused` to see only what was withheld. + pub outcome: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of outcomes to return. Defaults to 50; maximum is 200. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor from a previous response; returns outcomes older than it. Cursors are not parseable and are only valid against this endpoint. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor from a previous response; returns outcomes newer than it. Suited to a UI loading newer entries. To poll for everything recorded since a point in time, prefer `since` with a little overlap and de-duplicate on `id` — `after_cursor` can miss an attempt recorded in the same millisecond as the cursor's own row. + pub after_cursor: Option, +} + +/// Sets the binding's deposit target — the internal staging thread the +/// deposit pipe copies this channel's mirror content into. Pass a `null` +/// `thread_id` to turn the pipe off. +/// +/// The target is validated server-side: it must exist, belong to the +/// binding's app and org, and never be a Slack mirror thread. Customer +/// bindings (bound `team_id`) additionally require a team-owned private +/// thread with no participant list, so the staging read ACL stays governed +/// by the channel-membership projection. Re-pointing or clearing an +/// existing target purges the old thread's deposit entries. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SlackChannelBindingsChannelDepositThreadInput { + /// Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. + pub slack_team_id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Staging thread ID (primary key, `thr_…`) deposits should flow into. Pass `null` to turn the pipe off. + pub thread_id: Option, +} + +/// Query parameters for get_api_v1_solution_categories. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1SolutionCategoriesParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to retrieve, 1-indexed. Defaults to `1`. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of solution categories to return per page. Defaults to `25`. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only categories whose key exactly matches one of the provided values. + pub keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only categories whose parent key matches one of the provided values. Pass an empty array to return root-level categories. + pub parent_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only the category whose `lookup_key` exactly matches this value. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only categories whose `virtual_path` starts with this prefix. + pub path_prefix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to categories owned by the specified scopes. Accepted values are `"system"` and `"org"`. Omit to include all ownership scopes visible to the caller. + pub owners: Option>, +} + +/// Query parameters for get_api_v1_solution_instances. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1SolutionInstancesParams { + /// ID of the installed solution template whose customer instances should be listed. + pub solution_template_config_id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of instances to return. Defaults to 50; maximum is 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the preceding page. Omit to retrieve the first page. + pub after_cursor: Option, +} + +/// Query parameters for get_api_v1_solution_tags. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1SolutionTagsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to return. Defaults to 1. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of solution tags to return per page. Defaults to 25. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only solution tags whose `key` exactly matches one of the provided values. + pub keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only the solution tag whose `lookup_key` exactly matches this value. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only solution tags whose `virtual_path` starts with this prefix. + pub path_prefix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to one or more owner scopes. Accepted values are `"system"` (app-level system tags) and `"org"` (tags belonging to the caller's organization). Omit to include all scopes visible to the caller. + pub owners: Option>, +} + +/// Query parameters for get_api_v1_solutions. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1SolutionsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to return. Defaults to `1`. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of Solutions per page. Defaults to `25`. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter to the Solution whose `lookup_key` matches exactly. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter to Solutions whose `virtual_path` starts with this prefix. + pub path_prefix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to a subset of owner scopes. Accepted values: `"system"` (app-level Solutions) and `"org"` (viewer's org-level Solutions). Omit to include all scopes the viewer can see. + pub owners: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsInputSolutionBundleConfigsItem { + /// Full text content of the configuration file. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the configuration content, e.g. `"application/x-yaml"` or `"application/json"`. `null` if not specified. + pub content_type: Option, + /// Bundle-relative path to this config file. The path determines the config kind and its storage identity within the installation. + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsInputSolutionBundleSetupActionsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// List of other setup action identifiers that must be completed before this action becomes actionable. + pub depends_on: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Markdown-formatted instructions or context shown beneath the checklist item. `null` if not provided. + pub description: Option, + /// Category of setup step. One of `"env_var"` (configure an environment variable), `"install"` (complete an installation step), `"custom"` (a user-defined action), or `"integration"` (authorize an OAuth-backed MCP server integration). + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Kind-specific configuration for the action. For `"env_var"` steps this typically includes `key` and `scope`; for `"install"` steps it includes `installation_kind`; for `"integration"` steps it includes `mcp_server_ref`. Shape varies by `kind`. + pub params: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, this action must be completed before the checklist progress bar reaches 100%. Defaults to `true`. + pub required: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Numeric sort position controlling the display order of this action in the checklist. Defaults to `0` when not specified. + pub sort_order: Option, + /// Short human-readable label displayed in the setup checklist. + pub title: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Configuration passed to the runtime verifier to determine whether the action has been completed, e.g. `{"type": "secret_present"}`. `null` if no automated verification is configured. + pub verify_config: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsInputSolutionBundleSkillsItemFilesItem { + /// Full text content of the file. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the file content. Defaults to a value inferred from the file extension when omitted. + pub content_type: Option, + /// Path of this file relative to the skill folder root, e.g. `"skills/my-skill/helpers.md"`. + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsInputSolutionBundleSkillsItem { + /// Full text content of the `SKILL.md` file. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the `SKILL.md` content. Defaults to `text/markdown` when omitted. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Additional files nested inside the skill folder, each with its own path and content. + pub files: Option>, + /// Bundle-relative path to the skill root, which must end in `/SKILL.md` (e.g. `"skills/my-skill/SKILL.md"`). + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsInputSolutionBundleSolutionFilesItem { + /// Raw content of the file. When `data_encoding` is `"base64"`, this must be a valid base64-encoded string. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the file. Defaults to a value inferred from the file extension when omitted. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Encoding of `content`. `"raw"` (default) stores the value verbatim. `"base64"` decodes the value server-side before storage — use this to ship binary assets (PDFs, images) through a JSON body. + pub data_encoding: Option, + /// Path of this file relative to the solution root (e.g. `README.md`, `assets/diagram.png`). + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsInputSolutionBundleSolution { + /// Raw solution.yaml body (YAML or JSON). Describes the solution structure, template references, and asset declarations. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of `content`. Defaults to `application/x-yaml`; pass `application/json` when submitting JSON. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Component files (READMEs, diagrams, fixtures) referenced by the solution.yaml via `path://` URIs. Each entry is persisted as a child file record. + pub files: Option>, + /// Stable lookup key for this solution. A suffix is appended at install time to namespace the stored config. + pub lookup_key: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsInputSolutionBundleTemplate { + /// Full text content of the agent template file, typically a YAML document. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the template content. Defaults to `application/x-yaml` when omitted. + pub content_type: Option, + /// Bundle-relative path to the template file, used to derive its storage identity (e.g. `"agent.yaml"`). + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsInputSolutionBundleTemplatesItem { + /// Full text content of the agent template file, typically a YAML document. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the template content. Defaults to `application/x-yaml` when omitted. + pub content_type: Option, + /// Bundle-relative path to the template file, used to derive its storage identity (e.g. `"agent.yaml"`). + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsInputSolutionBundle { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Additional configs of any kind that the solution.yaml references and that should be upserted as part of this install. + pub configs: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// String prepended (with a `-` separator) to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Typical value is `solutions-`. + pub lookup_key_prefix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// String appended to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Should be stable for a given install and unique per attempt. + pub lookup_key_suffix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Post-install setup checklist items for the wrapped template. Allowed only when the bundle contains a single template and that template's body does not already declare its own `setup_actions`. Omit when bundling multiple templates. + pub setup_actions: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Skill bundles (root config plus supporting files) that this solution depends on. + pub skills: Option>, + /// The solution config to install, including the solution.yaml body and any referenced component files. + pub solution: PostApiV1SolutionsInputSolutionBundleSolution, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Convenience shorthand for supplying a single template. Equivalent to setting `templates: [template]`. Mutually exclusive with `templates`. Use `templates` directly when bundling multiple sibling templates. + pub template: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Ordered list of templates the solution wraps. The first entry is the deployable template; additional entries are sibling templates it references via `template_path:`. Mutually exclusive with `template`. + pub templates: Option>, +} + +/// Imports a Solution and its bundled configs (skills, scripts, templates, files) +/// into the library for the target scope. Two mutually exclusive import modes +/// are supported: pass `solution` to re-import an existing system-owned catalog +/// Solution by ID or `lookup_key`, or pass `solution_bundle` to supply a +/// self-contained inline bundle. Exactly one must be present. +/// +/// The operation upserts the bundle in a single transaction. When `dry_run` is +/// `true` the same pipeline runs but the transaction is rolled back — no rows are +/// persisted and the response reflects what would have been written. The +/// response shape is the same in both cases: the Solution summary plus +/// `installed_configs` listing each config the import created or would create. +/// +/// Pairs with `POST /api/v1/solutions/:solution/install`: this endpoint puts the +/// Solution into the library; install provisions a runtime resource (Agent, +/// AgentRoutine, AgentTool, etc.) from an already-imported Solution. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, runs the full import pipeline but rolls back the transaction — no rows are persisted. The response reflects what would have been written. Defaults to `false`. + pub dry_run: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) for the import destination scope. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config ID (`cfg_...`) or `lookup_key` of an existing system-owned, org-less Solution to import into the target scope. Mutually exclusive with `solution_bundle`. + pub solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Self-contained inline bundle containing the Solution metadata plus all bundled configs (skills, templates, configs, files). Mutually exclusive with `solution`. + pub solution_bundle: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) for the import destination scope. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) for the import destination scope. Only one of `org`, `team`, or `user` may be set. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Path prefix under which all uploaded configs' `virtual_path` values are anchored (for example `solutions/`). Stable per install; omit to use no prefix. + pub virtual_path_prefix: Option, +} + +/// Query parameters for get_api_v1_solutions__solution_image. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1SolutionsSolutionImageParams { + /// HMAC capability token authorizing access to this Solution's cover. Obtained from the `image_url` minted when the Solution was serialized. + pub token: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cache key minted alongside the token; changes when the Solution changes. Ignored by token verification. + pub v: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Bundled asset path of the image to serve (for example `images/setup.png`). Must be one of the paths the Solution body currently declares in `image`/`screenshots` — anything else is a `404`. When absent the declared cover (`image:`) is served. + pub file: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionInstallInputAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionInstallInputAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionInstallInputAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionInstallInputAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionInstallInputDetailsPrefills { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected. + pub payload: Option>, +} + +/// Contract-defined values for PostApiV1SolutionsSolutionInstallInputDetailsType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum PostApiV1SolutionsSolutionInstallInputDetailsType { + /// The automation wire value. + #[serde(rename = "automation")] + Automation, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionInstallInputDetails { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Instance-specific locked payload and participant values. Payload paths and participant slots are validated against the installed template's resolved input schema and workflow. + pub prefills: Option, + #[serde(rename = "type")] + /// Install-details discriminator. Always `automation` for this variant. + pub type_: PostApiV1SolutionsSolutionInstallInputDetailsType, +} + +/// Provisions a runtime resource from an already-imported Solution. The type of +/// resource created depends on the template the Solution wraps: an +/// `AgentTemplate` produces an Agent, an `AutomationTemplate` produces an +/// Automation, and attachment templates (`AgentRoutineTemplate`, +/// `AgentToolTemplate`, `AgentSkillTemplate`, `AgentComputerTemplate`) attach a +/// sub-resource to an existing Agent specified by `target`. +/// +/// For Solutions that bundle more than one template, pass `template` (the ID or +/// `lookup_key` of the desired template) to select which one to provision. +/// Single-template Solutions do not require `template`. +/// +/// Pairs with `POST /api/v1/solutions` (import): import puts the Solution into +/// the library; install provisions a runtime resource from it. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionInstallInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list applied atomically to a provisioned Agent or Automation. Team grants are useful when installing into a cross-organization collaboration team. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, automatically imports the Solution into the target tenant before installing if the org-scoped copy does not yet exist. Requires either an authenticated org user (member or admin) or a platform-privileged caller (S2S, developer JWT) that also supplies an explicit `org` param. Defaults to `false`; without it the endpoint returns 404 when the org-scoped Solution is missing. + pub allow_auto_import: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template-specific install options selected by the `type` discriminator. AutomationTemplate installs accept `{type: "automation", prefills: ...}`. + pub details: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Values applied to parameterized AgentTemplate prose during a root Agent install. Use `{values: {customer_label: "Acme"}}`. + pub install_inputs: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lookup key override for the provisioned resource (for example, the Agent's `agent_key`). + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Suffix appended to every `config_ref:` resolution at install time. Should be stable per logical install and unique per attempt — allows the same Solution to be installed multiple times in the same app without collisions. + pub lookup_key_suffix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name override for a provisioned Agent or Automation. Ignored for attachment Solutions. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) for the install destination scope. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID or `lookup_key` of the parent Agent to attach to. Required when installing an `AgentRoutineTemplate`, `AgentToolTemplate`, `AgentSkillTemplate`, or `AgentComputerTemplate` Solution, since those produce sub-resources attached to an existing Agent. Omit for `AgentTemplate` and `AutomationTemplate` Solutions, which provision standalone resources. + pub target: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`team_...`) for the install destination scope. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config ID (`cfg_...`) or `lookup_key` of the template within the Solution to provision. Required when the Solution bundles more than one template; omit for single-template Solutions, where the only template is selected implicitly. + pub template: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) for the install destination scope. + pub user: Option, +} + +/// Query parameters for get_api_v1_solutions__solution_readme. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1SolutionsSolutionReadmeParams { + /// Signed URL token minted by the list or show endpoint. Expires after one hour. + pub token: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path of the asset to retrieve (for example `images/hero.png`). When present the response is the raw asset bytes with its real `Content-Type`; when absent the response is the README markdown. + pub file: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionUpgradeInputSolutionBundleConfigsItem { + /// Full text content of the configuration file. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the configuration content, e.g. `"application/x-yaml"` or `"application/json"`. `null` if not specified. + pub content_type: Option, + /// Bundle-relative path to this config file. The path determines the config kind and its storage identity within the installation. + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionUpgradeInputSolutionBundleSetupActionsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// List of other setup action identifiers that must be completed before this action becomes actionable. + pub depends_on: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Markdown-formatted instructions or context shown beneath the checklist item. `null` if not provided. + pub description: Option, + /// Category of setup step. One of `"env_var"` (configure an environment variable), `"install"` (complete an installation step), `"custom"` (a user-defined action), or `"integration"` (authorize an OAuth-backed MCP server integration). + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Kind-specific configuration for the action. For `"env_var"` steps this typically includes `key` and `scope`; for `"install"` steps it includes `installation_kind`; for `"integration"` steps it includes `mcp_server_ref`. Shape varies by `kind`. + pub params: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, this action must be completed before the checklist progress bar reaches 100%. Defaults to `true`. + pub required: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Numeric sort position controlling the display order of this action in the checklist. Defaults to `0` when not specified. + pub sort_order: Option, + /// Short human-readable label displayed in the setup checklist. + pub title: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Configuration passed to the runtime verifier to determine whether the action has been completed, e.g. `{"type": "secret_present"}`. `null` if no automated verification is configured. + pub verify_config: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionUpgradeInputSolutionBundleSkillsItemFilesItem { + /// Full text content of the file. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the file content. Defaults to a value inferred from the file extension when omitted. + pub content_type: Option, + /// Path of this file relative to the skill folder root, e.g. `"skills/my-skill/helpers.md"`. + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionUpgradeInputSolutionBundleSkillsItem { + /// Full text content of the `SKILL.md` file. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the `SKILL.md` content. Defaults to `text/markdown` when omitted. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Additional files nested inside the skill folder, each with its own path and content. + pub files: Option>, + /// Bundle-relative path to the skill root, which must end in `/SKILL.md` (e.g. `"skills/my-skill/SKILL.md"`). + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionUpgradeInputSolutionBundleSolutionFilesItem { + /// Raw content of the file. When `data_encoding` is `"base64"`, this must be a valid base64-encoded string. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the file. Defaults to a value inferred from the file extension when omitted. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Encoding of `content`. `"raw"` (default) stores the value verbatim. `"base64"` decodes the value server-side before storage — use this to ship binary assets (PDFs, images) through a JSON body. + pub data_encoding: Option, + /// Path of this file relative to the solution root (e.g. `README.md`, `assets/diagram.png`). + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionUpgradeInputSolutionBundleSolution { + /// Raw solution.yaml body (YAML or JSON). Describes the solution structure, template references, and asset declarations. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of `content`. Defaults to `application/x-yaml`; pass `application/json` when submitting JSON. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Component files (READMEs, diagrams, fixtures) referenced by the solution.yaml via `path://` URIs. Each entry is persisted as a child file record. + pub files: Option>, + /// Stable lookup key for this solution. A suffix is appended at install time to namespace the stored config. + pub lookup_key: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionUpgradeInputSolutionBundleTemplate { + /// Full text content of the agent template file, typically a YAML document. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the template content. Defaults to `application/x-yaml` when omitted. + pub content_type: Option, + /// Bundle-relative path to the template file, used to derive its storage identity (e.g. `"agent.yaml"`). + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionUpgradeInputSolutionBundleTemplatesItem { + /// Full text content of the agent template file, typically a YAML document. + pub content: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the template content. Defaults to `application/x-yaml` when omitted. + pub content_type: Option, + /// Bundle-relative path to the template file, used to derive its storage identity (e.g. `"agent.yaml"`). + pub relative_path: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionUpgradeInputSolutionBundle { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Additional configs of any kind that the solution.yaml references and that should be upserted as part of this install. + pub configs: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// String prepended (with a `-` separator) to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Typical value is `solutions-`. + pub lookup_key_prefix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// String appended to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Should be stable for a given install and unique per attempt. + pub lookup_key_suffix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Post-install setup checklist items for the wrapped template. Allowed only when the bundle contains a single template and that template's body does not already declare its own `setup_actions`. Omit when bundling multiple templates. + pub setup_actions: + Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Skill bundles (root config plus supporting files) that this solution depends on. + pub skills: Option>, + /// The solution config to install, including the solution.yaml body and any referenced component files. + pub solution: PostApiV1SolutionsSolutionUpgradeInputSolutionBundleSolution, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Convenience shorthand for supplying a single template. Equivalent to setting `templates: [template]`. Mutually exclusive with `templates`. Use `templates` directly when bundling multiple sibling templates. + pub template: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Ordered list of templates the solution wraps. The first entry is the deployable template; additional entries are sibling templates it references via `template_path:`. Mutually exclusive with `template`. + pub templates: Option>, +} + +/// Applies an incoming bundle to an already-installed Solution in a single atomic +/// transaction, bringing its configs in line with the new bundle. Config IDs are +/// preserved across the upgrade. Configs that existed in the old bundle but are +/// absent from the new one are orphaned (top-level) or hard-deleted (child rows). +/// +/// Two mutually exclusive source modes: pass `target_solution` to pull the +/// incoming bundle from an existing Solution by ID or `lookup_key`, or pass +/// `solution_bundle` to supply a complete inline bundle directly. Exactly one +/// must be present. +/// +/// When `dry_run` is `true` the full diff is computed and returned but no +/// changes are written. Pass the dry-run response's `review_fingerprint` as +/// `expected_review_fingerprint` when applying to guard against the bundle +/// changing between review and apply. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionUpgradeInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, permits an incoming `solution_version` lower than the currently installed version. Defaults to `false`. + pub allow_downgrade: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, computes and returns the full upgrade diff without persisting any changes. Defaults to `false`. + pub dry_run: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional stale-review guard. Pass the `review_fingerprint` returned by a prior `dry_run` call to ensure the bundle has not changed between review and apply. + pub expected_review_fingerprint: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) used to resolve org-scoped `lookup_key` values. Config IDs (`cfg_...`) are globally unique and do not require this. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Complete inline bundle for a direct upgrade, including Solution metadata, templates, skills, configs, files, and setup actions. Mutually exclusive with `target_solution`. + pub solution_bundle: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Config ID (`cfg_...`) or `lookup_key` of the Solution to use as the incoming upgrade source. Mutually exclusive with `solution_bundle`. + pub target_solution: Option, +} + +/// Records a `solution_viewed` analytics event for the identified Solution and +/// returns `204 No Content`. Fired by the marketplace when a Solution's detail +/// page is rendered in a browser, so publishers can see impressions alongside +/// installs in their Solution analytics. +/// +/// Visibility matches `GET /api/v1/solutions/:solution`: unauthenticated callers +/// (the logged-out marketplace) can only track Solutions published to the public +/// catalog; anything the caller could not retrieve returns 404 and records +/// nothing. +/// +/// Pass `anonymous` (the analytics visitor ID) so logged-out views can be +/// counted as unique viewers. The event's Solution and publisher attribution are +/// resolved server-side from the Solution row — never from request input. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1SolutionsSolutionViewInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Analytics visitor ID to attribute the view to, for unique-viewer counting. Same identifier the `POST /api/v1/t` events use; the marketplace sends it on every view. Authenticated callers additionally get user attribution from their session. + pub anonymous: Option, +} + +/// Query parameters for get_api_v1_tasks__task. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning team (`tem_...`) for privileged calls. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning user (`usr_...`) for privileged calls. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning agent (`agi_...`) for privileged calls. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit organization (`org_...`) for privileged calls; pass null when unscoped. + pub org: Option, +} + +/// Updates the supplied fields on a task and returns the complete updated task. +/// Authenticated users use their session identity. App-scoped developer and +/// server-to-server callers must explicitly supply the task's `org` and owner. +/// `team` or `user` identifies that owner; when neither is present, `agent` +/// identifies an agent-owned task. With a team or user owner, `agent` identifies +/// the acting principal. Every reference is validated before the update. +/// +/// A cooperating coding-session client may supply both `lease_id` and +/// `lease_session_id`. The task aggregate fences that update against the live +/// lease and records server-sourced session provenance. Omitting both remains a +/// normal authorized human/API update. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1TasksTaskInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit agent (`agi_...`). It is the owner when `team` and `user` are absent; otherwise it is the acting principal. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated long-form description. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated due date in ISO 8601 format, or null to clear it. + pub due_date: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current caller-held lease UUID. Must be paired with `lease_session_id`. + pub lease_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current coding-session UUID. Must be paired with `lease_id`. + pub lease_session_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement related-links object. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement task metadata object. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated display name for the task. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit organization (`org_...`) for a developer or server-to-server call. Pass null for an owner outside an organization. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Assign to an agent by public ID (`agi_...`). + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Assign to a user by public ID (`usr_...`). + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Move this task under a top-level parent (`tsk_...`), or pass null to promote it to a top-level task. A task that has subtasks cannot become one. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated priority from 0 (highest) to 4 (lowest). + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated status: `open`, `in_progress`, or `done`. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement tag list (max 20, each up to 40 characters; normalized to lowercase). Pass an empty array to clear all tags. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning team (`tem_...`) for a developer or server-to-server call. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit user (`usr_...`) for a developer or server-to-server call. With `team`, this identifies the acting team member. + pub user: Option, +} + +/// Query parameters for get_api_v1_tasks__task_activity. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskActivityParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning team (`tem_...`) for privileged calls. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning user (`usr_...`) for privileged calls. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning agent (`agi_...`) for privileged calls. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit organization (`org_...`) for privileged calls; pass null when unscoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum entries to return. Capped at 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the previous page. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskActivityResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Machine-readable type of the event, e.g. `"task.status_changed"` or `"task.comment_added"`. + pub event_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable sentence describing the activity, suitable for display in an activity feed. + pub sentence: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this activity event occurred (ISO 8601). + pub timestamp: Option>, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskActivityResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + /// API field. + pub data: Vec, + /// API field. + pub has_more: bool, +} + +/// Query parameters for get_api_v1_tasks__task_blocking. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockingParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning team (`tem_...`) for privileged calls. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning user (`usr_...`) for privileged calls. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning agent (`agi_...`) for privileged calls. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit organization (`org_...`) for privileged calls; pass null when unscoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum tasks to return. Capped at 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the previous page. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockingResponseDataItemCreatedByActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockingResponseDataItemCreatedByActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockingResponseDataItemCurrentLease { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the coding session. + pub harness: String, + /// Display name supplied by the coding session that holds the lease. + pub session_name: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockingResponseDataItemOwnerActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockingResponseDataItemOwnerActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockingResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind. + pub blocked_by_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open. + pub closed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of comments posted on this task. + pub comments_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted). + pub created_by_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted. + pub created_by_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted. + pub created_by_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included. + pub current_lease: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Long-form description or notes for the task. `null` if no description has been provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). `null` if no due date is set. + pub due_date: Option>, + /// Task ID (`tsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read. + pub is_blocked: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set. + pub metadata: Option>, + /// Human-readable title of the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted). + pub owner_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment. + pub sandbox: Option, + /// Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks. + pub subtasks_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockingResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + /// API field. + pub data: Vec, + /// API field. + pub has_more: bool, +} + +/// Query parameters for get_api_v1_tasks__task_subtasks. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskSubtasksParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning team (`tem_...`) for privileged calls. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning user (`usr_...`) for privileged calls. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning agent (`agi_...`) for privileged calls. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit organization (`org_...`) for privileged calls; pass null when unscoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum subtasks to return. Capped at 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the previous page. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskSubtasksResponseDataItemCreatedByActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskSubtasksResponseDataItemCreatedByActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskSubtasksResponseDataItemCurrentLease { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the coding session. + pub harness: String, + /// Display name supplied by the coding session that holds the lease. + pub session_name: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskSubtasksResponseDataItemOwnerActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskSubtasksResponseDataItemOwnerActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskSubtasksResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind. + pub blocked_by_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open. + pub closed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of comments posted on this task. + pub comments_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted). + pub created_by_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted. + pub created_by_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted. + pub created_by_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included. + pub current_lease: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Long-form description or notes for the task. `null` if no description has been provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). `null` if no due date is set. + pub due_date: Option>, + /// Task ID (`tsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read. + pub is_blocked: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set. + pub metadata: Option>, + /// Human-readable title of the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted). + pub owner_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment. + pub sandbox: Option, + /// Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks. + pub subtasks_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskSubtasksResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + /// API field. + pub data: Vec, + /// API field. + pub has_more: bool, +} + +/// Query parameters for get_api_v1_tasks__task_blockers. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockersParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning team (`tem_...`) for privileged calls. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning user (`usr_...`) for privileged calls. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning agent (`agi_...`) for privileged calls. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit organization (`org_...`) for privileged calls; pass null when unscoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum blockers to return. Capped at 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the previous page. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockersResponseDataItemCreatedByActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockersResponseDataItemCreatedByActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockersResponseDataItemCurrentLease { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the coding session. + pub harness: String, + /// Display name supplied by the coding session that holds the lease. + pub session_name: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockersResponseDataItemOwnerActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockersResponseDataItemOwnerActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockersResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind. + pub blocked_by_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open. + pub closed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of comments posted on this task. + pub comments_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted). + pub created_by_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted. + pub created_by_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted. + pub created_by_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included. + pub current_lease: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Long-form description or notes for the task. `null` if no description has been provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). `null` if no due date is set. + pub due_date: Option>, + /// Task ID (`tsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read. + pub is_blocked: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set. + pub metadata: Option>, + /// Human-readable title of the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted). + pub owner_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment. + pub sandbox: Option, + /// Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks. + pub subtasks_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskBlockersResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + /// API field. + pub data: Vec, + /// API field. + pub has_more: bool, +} + +/// Records that the task in `blocker` blocks the specified task and returns +/// the updated task. Blocking is informational — the blocked task can still +/// change status — and derived at read time, so the task stops reporting +/// `is_blocked` as soon as every blocker is done. The blocker must belong to +/// the same owner (team or user) as the task; self-blocking and blocking a +/// task that already blocks the blocker (a direct cycle) are rejected. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TasksTaskBlockersInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning agent (`agi_...`) for privileged calls. + pub agent: Option, + /// ID of the task that blocks this task (`tsk_...`). + pub blocker: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit organization (`org_...`) for privileged calls; pass null when unscoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning team (`tem_...`) for privileged calls. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning user (`usr_...`) for privileged calls. + pub user: Option, +} + +/// Query parameters for get_api_v1_tasks__task_comments. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskCommentsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning team (`tem_...`) for privileged calls. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning user (`usr_...`) for privileged calls. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit owning agent (`agi_...`) for privileged calls. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit organization (`org_...`) for privileged calls; pass null when unscoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum comments to return. Capped at 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the previous page. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskCommentsResponseDataItemAuthorActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskCommentsResponseDataItemAuthorActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskCommentsResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved author details including `id`, `name`, `alias`, and `profile_picture`. `null` if no author is set or the author cannot be resolved (e.g. authoring agent was deleted). + pub author_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that posted this comment (`agi_...`). `null` if the author is a human user, or if the authoring agent was later deleted. + pub author_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who posted this comment (`usr_...`). `null` if the author is an agent, or if author provenance was cleared after the authoring agent was deleted. + pub author_user: Option, + /// Plain-text body of the comment. + pub body: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this comment was posted (ISO 8601). + pub created_at: Option>, + /// Comment ID (`tcmt_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization that owns this comment (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sandbox ID this comment is scoped to. `null` for comments outside a sandbox environment. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the task this comment belongs to (`tsk_...`). + pub task: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team the task belongs to (`tem_...`). `null` if not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this comment was last edited (ISO 8601). + pub updated_at: Option>, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TasksTaskCommentsResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + /// API field. + pub data: Vec, + /// API field. + pub has_more: bool, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TasksTaskCommentsInputComment { + /// The plain-text content of the comment. Must be a non-empty string. + pub body: String, +} + +/// Posts a new comment on the specified task and returns the created comment. +/// The task's owner is resolved from the task itself. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TasksTaskCommentsInput { + /// Parameters for the comment to create, including its body. + pub comment: PostApiV1TasksTaskCommentsInputComment, +} + +/// Replaces the body of an existing comment and returns the updated comment. +/// The task's owner is resolved from the task itself. +/// +/// Only the comment's author, an admin of the comment's organization, or an +/// admin of the owning team may edit a comment. Returns `403 Forbidden` +/// otherwise. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1TasksTaskCommentsCommentInput { + /// Replacement body for the comment. Must be non-empty. + pub body: String, +} + +/// Atomically claims a user-assigned task for the authenticated user's coding +/// session. The caller generates and retains both UUIDs. An exact retry returns +/// the existing lease without extending it; another live holder produces a +/// conflict. Developer and server-to-server credentials cannot impersonate the +/// assigned user. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TasksTaskLeaseInput { + /// Bounded harness identifier. + pub harness: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Requested lease lifetime in seconds; the task aggregate enforces its bounds. + pub lease_duration_seconds: Option, + /// Caller-generated lease UUID. + pub lease_id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Conservatively reject the claim when the current task projection has unfinished blockers. + pub require_ready: Option, + /// Caller-generated coding-session UUID. + pub session_id: String, + /// Human-readable coding-session label. + pub session_name: String, +} + +/// Renews the authenticated assignee's matching live task lease. Both +/// caller-generated UUIDs must match the aggregate's current lease. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TasksTaskLeaseRenewInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Requested renewed lifetime in seconds; the task aggregate enforces its bounds. + pub lease_duration_seconds: Option, + /// Current caller-held lease UUID. + pub lease_id: String, + /// Current coding-session UUID. + pub session_id: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TasksTaskLinksInput { + /// External container ID. + pub external_scope: String, + /// External object ID. + pub object_id: String, + /// External object type. + pub object_type: String, +} + +/// Query parameters for get_api_v1_team_memberships. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamMembershipsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to memberships belonging to these team IDs (`tm_...`). Multiple values are combined with OR. + pub team: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to memberships held by these user IDs (`usr_...`). Multiple values are combined with OR. + pub user: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to memberships held by these agent IDs (`agt_...`). Multiple values are combined with OR. + pub agent: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to retrieve, starting at `1`. Defaults to `1`. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of memberships to return per page. Defaults to `25`. + pub page_size: Option, +} + +/// Query parameters for get_api_v1_teams. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Page number to retrieve, starting at 1. Defaults to 1. + pub page: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of teams to return per page. Defaults to 25. + pub page_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full-text search string matched against team name and description. + pub search: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Structured metadata filter expression. Only teams whose metadata satisfies the expression are returned. + pub metadata: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter teams by membership status. `"joined"` returns only teams the caller is a member of. `"joinable"` returns ACL-visible teams the caller has not yet joined. Omit to return all visible teams. + pub membership: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsResponseDataItemAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsResponseDataItemAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsResponseDataItemAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsResponseDataItemAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list governing visibility and join permissions for this team. `null` when no ACL restrictions are applied and the team inherits default access rules. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer application this team belongs to (`dap_...`). `null` if the team is not scoped to an app. + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Aggregated badge counts for the team, keyed by category. `null` when badge data is not loaded. + pub badges: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this team was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of the team's purpose. `null` if not set. + pub description: Option, + /// Team ID (`tem_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The authenticated viewer's role on this team. One of `"owner"`, `"admin"`, or `"member"`. `null` if the viewer is not a member. + pub membership_status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to this team. Returns an empty object when no metadata has been set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the team. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this team belongs to (`org_...`). `null` if the team is not org-scoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this team is scoped to (`dsb_...`). `null` outside sandbox contexts. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL-safe slug for the team, derived from the team name. `null` if not set. + pub slug: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this team was last updated (ISO 8601). + pub updated_at: Option>, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsResponse { + /// Array of team objects for the current page. + pub data: Vec, + /// `true` if there is a subsequent page of results. + pub has_next: bool, + /// `true` if there is a preceding page of results. + pub has_prev: bool, + /// The current page number. + pub page: i64, + /// The number of results per page. + pub page_size: i64, + /// Total number of teams matching the query across all pages. + pub total_entries: i64, + /// Total number of pages given the current `page_size`. + pub total_pages: i64, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsInputAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsInputAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsInputAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsInputAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Creates a new team and returns the created team object. The authenticated +/// user becomes the team's owner. +/// +/// When `app` is supplied, the request is scoped to that app and the caller +/// must hold the corresponding app scope. Omit `org` unless you want the team +/// pinned to a specific organization. A default chat thread is provisioned for +/// the team automatically after creation. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control configuration for the team. Controls who can discover and join the team. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional human-readable description of the team's purpose. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional retry key. Replays in the same app, organization, and sandbox return the original team. + pub idempotency_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value pairs you can attach to the team for your own use. Values must be strings. + pub metadata: Option>, + /// Display name for the team. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) to associate the team with. Omit to create the team without an org affiliation. + pub org: Option, +} + +/// Adds a principal to a team using a 12-character invite code. The invite +/// code can be supplied as either `join_code` or `invite_code`; both are +/// accepted for backwards compatibility. +/// +/// For user-authenticated requests, the currently authenticated user is added +/// to the team. For server-to-server requests, you must supply either `agent` +/// (to add an agent) or `user` (to add a specific user by ID). If the user +/// is already a member of the team, the request succeeds without creating a +/// duplicate membership. +/// +/// This endpoint is rate-limited to 10 requests per minute per IP address to +/// prevent invite-code enumeration. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsJoinByCodeInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agent_...`) to add to the team. When provided, the agent is joined instead of the authenticated user. Requires a server-to-server session. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// 12-character invite code — alias for `join_code` accepted for backwards compatibility. + pub invite_code: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// 12-character invite code that identifies the team. Mutually usable with `invite_code`. + pub join_code: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`user_...`) to add to the team. Required for server-to-server requests when `agent` is not supplied. + pub user: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1TeamsTeamInputAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1TeamsTeamInputAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1TeamsTeamInputAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1TeamsTeamInputAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1TeamsTeamInputProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Base64-encoded binary image data. + pub data: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the image, used for storage metadata. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. + pub mime_type: Option, +} + +/// Updates one or more attributes of the team identified by `team`. Only the +/// fields you provide are changed; omitted fields are left as-is. +/// +/// To replace the team's profile picture, supply the `profile_picture` object +/// with base64-encoded image data. The previous picture is deleted after the +/// new one is successfully uploaded. When `app` is present, the caller must hold +/// the corresponding app scope. The caller must be a team owner or org admin. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1TeamsTeamInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New access control configuration for the team. Replaces the existing ACL. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New human-readable description of the team's purpose. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value pairs to set on the team. Replaces the existing metadata map entirely. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New display name for the team. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New profile picture for the team. Provide this object to upload and replace the current picture. + pub profile_picture: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamArtifactsResponseDataItemImageSource { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamArtifactsResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that produced this artifact (`agt_...`). `null` if not agent-produced. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the current version's file, e.g. `"text/csv"` or `"image/png"`. `null` if no file is attached. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the artifact was first created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the current (latest published) artifact version (`artv_...`). `null` if no version has been published. + pub current_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional longer description of the artifact's contents or purpose. `null` if not set. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Storage file ID for the current version (`fil_...`). `null` if no file is attached. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the current version's file, e.g. `"output.csv"`. `null` if no file is attached. + pub file_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short-lived signed URL for downloading the current version's file. `null` if no file is attached. + pub file_url: Option, + /// Artifact ID (`art_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Image source metadata for rendering the current version's file inline. Present only when `content_type` starts with `"image/"`. `null` otherwise. + pub image_source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable name for the artifact, e.g. `"Q2 Report"`. `null` if not set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this artifact belongs to (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the sandbox environment associated with this artifact. `null` if not sandbox-scoped. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this artifact (`tea_...`). `null` if not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread in which this artifact was created (`thr_...`). `null` if not thread-scoped. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the artifact record was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this artifact (`usr_...`). `null` if not user-scoped. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current version number of the artifact. Increments each time a new version is published. + pub version: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamArtifactsResponse { + /// Array of artifact objects belonging to the team. + pub data: Vec, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsTeamInvitesResponse { + /// Six-character alphanumeric join code. Present this value to the join-team endpoint to add a user to the team. + pub code: String, +} + +/// Adds a principal to a team that is visible to the authenticated user. +/// +/// By default, the currently authenticated user joins the team. Provide `agent` +/// to add an agent to the team instead — the caller must already be a member of +/// the team to do so. Provide `user` (by ID) or `email` to add another user from +/// your organization — the caller must be a team owner, team admin, or org admin. +/// Only one of `agent`, `user`, or `email` may be supplied per request. +/// +/// If the target principal is already a member of the team, the request succeeds +/// without creating a duplicate membership. Server-to-server callers are not +/// permitted to use this endpoint; use the invite-code endpoint instead. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsTeamJoinInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agent_...`) to add to the team. The caller must already be a member of the team. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address of a member of the caller's organization to add to the team. Requires team-owner, team-admin, or org-admin role. + pub email: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`user_...`) of a member of the caller's organization to add to the team. Requires team-owner, team-admin, or org-admin role. + pub user: Option, +} + +/// Query parameters for get_api_v1_teams__team_task_assignees. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTaskAssigneesParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit organization (`org_...`) for developer and server-to-server calls. Pass null for a team outside an organization. + pub org: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTaskAssigneesResponseDataItemActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTaskAssigneesResponseDataItemActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option, +} + +/// Contract-defined values for GetApiV1TeamsTeamTaskAssigneesResponseDataItemType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1TeamsTeamTaskAssigneesResponseDataItemType { + /// The user wire value. + #[serde(rename = "user")] + User, + /// The agent wire value. + #[serde(rename = "agent")] + Agent, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTaskAssigneesResponseDataItem { + /// Resolved display details for the assignable principal. + pub actor: GetApiV1TeamsTeamTaskAssigneesResponseDataItemActor, + /// User (`usr_...`) or agent (`agi_...`) ID. + pub id: String, + #[serde(rename = "type")] + /// Principal type: `user` or `agent`. + pub type_: GetApiV1TeamsTeamTaskAssigneesResponseDataItemType, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTaskAssigneesResponse { + /// Users and agents that can be assigned to tasks owned by the team. + pub data: Vec, +} + +/// Query parameters for get_api_v1_teams__team_custom_objects. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamCustomObjectsParams { + #[serde(rename = "type")] + /// Schema type identifier (`lookup_key`) that filters results to objects of this schema. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of objects to return per page. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of objects to skip before returning results. Use with `limit` for page-based pagination. + pub offset: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to objects whose `row_key` exactly matches this value. + pub row_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results to objects whose `sort_key` exactly matches this value. + pub sort_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full-text search string matched against the schema's configured `search_fields`. When provided, results are ordered by relevance score descending instead of creation time descending. + pub query: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamCustomObjectsResponseDataItemAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamCustomObjectsResponseDataItemAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamCustomObjectsResponseDataItemAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamCustomObjectsResponseDataItemAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamCustomObjectsResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list governing read and write access to this custom object. Only returned to resource owners and privileged or organization-admin viewers; `null` for everyone else. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the custom object was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Map of field names to their current values as defined by the object's schema type. + pub fields: Option>, + /// Unique identifier for the custom object (`cobj_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this object belongs to (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// An optional stable key used to identify this object by a caller-controlled string rather than its generated ID. `null` if not set. + pub row_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment this object is scoped to (`dsb_...`). `null` for production objects. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The lookup key of the schema type that defines this object's field structure. `null` if the schema type has not been set. + pub schema_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this object (`tem_...`). `null` if the object is not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the custom object was last modified (ISO 8601). `null` if the object has never been updated after creation. + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this object (`usr_...`). `null` if the object is not user-scoped. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optimistic concurrency version of the object. Increments with each successful update; pass this value in write operations to detect conflicting changes. + pub version: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamCustomObjectsResponse { + /// Array of custom object records for the current page. + pub data: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Pagination metadata for the response. + pub meta: Option>, +} + +/// Creates a new custom object owned by the specified team. The object is +/// instantiated against the schema identified by `type` (the schema's +/// `lookup_key`). All field values are validated against that schema's +/// field definitions before the object is persisted. +/// +/// The authenticated user must be a member of the team with sufficient +/// access. If the team is not found or the caller lacks access, the endpoint +/// returns 404. If `type` does not match a registered schema for the team's +/// organization, the endpoint also returns 404. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsTeamCustomObjectsInput { + /// Map of field values to set on the new object. Keys and value types must conform to the schema identified by `type`. + pub fields: std::collections::BTreeMap, + #[serde(rename = "type")] + /// Schema type identifier (`lookup_key`) that defines the object's fields and validation rules. + pub type_: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionCurrentSolutionOrgLogo { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionCurrentSolutionTemplatesItemDetailsInvokeContractParticipantsItem +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Workflow-authored explanation of the slot's role. `null` when the workflow declares none. + pub description: Option, + /// The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking. + pub name: String, + /// Whether the workflow requires this slot to be filled for the run to complete its embedded stages. + pub required: bool, + #[serde(rename = "type")] + /// The kind of principal the slot accepts. Currently always `"agent_user"` — the value supplied at invoke is an agent ID (`agi_...`). + pub type_: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionCurrentSolutionTemplatesItemDetailsInvokeContractPrefills +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected. + pub payload: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionCurrentSolutionTemplatesItemDetailsInvokeContract { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured. + pub input_schema: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs. + pub participants: Option>, + /// Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected. + pub prefills: GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionCurrentSolutionTemplatesItemDetailsInvokeContractPrefills, +} + +/// Contract-defined values for GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionCurrentSolutionTemplatesItemDetailsType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionCurrentSolutionTemplatesItemDetailsType +{ + /// The automation wire value. + #[serde(rename = "automation")] + Automation, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionCurrentSolutionTemplatesItemDetails { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Automation execution type (`invoked`, `scheduled`, or `trigger`). + pub automation_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning. + pub invoke_contract: Option, + #[serde(rename = "type")] + /// Template-details discriminator. Always `automation` for this variant. + pub type_: GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionCurrentSolutionTemplatesItemDetailsType, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionCurrentSolutionTemplatesItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details. + pub details: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`. + pub display_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template config ID (`cfg_...`). `null` for inline-only templates. + pub id: Option, + /// Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lookup key stamped on the template config at import time. `null` when no lookup key was assigned. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable virtual path assigned to the template config. `null` when no virtual path was set. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionCurrentSolution { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none. + pub category_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was first imported (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none. + pub events: Option>, + /// Solution config ID (`cfg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only. + pub image_url: Option, + /// Resource type. Always `"Solution"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise. + pub latest_solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise. + pub latest_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing display name declared in the Solution body. `null` when the Solution body does not set one. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo. + pub org_logo: + Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve. + pub org_slug: Option, + /// Owner scopes this Solution appears under. Members: `"system"` (app-level system scope) and/or `"org"` (viewer's org scope). + pub owners: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only. + pub screenshot_urls: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it. + pub solution_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Semver string declared in the Solution body (e.g. `"1.2.0"`). `null` when the body does not declare a version. + pub solution_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Freeform tag keys declared in the Solution body. An empty array when the body declares none. + pub tag_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Wrapped template kind — `"AgentTemplate"`, `"AutomationTemplate"`, `"AgentRoutineTemplate"`, `"AgentToolTemplate"`, `"AgentComputerTemplate"`, or `"SolutionTemplateRef"` for ref-mode bundles. + pub template_kind: Option, + /// Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references. + pub templates: Vec< + GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionCurrentSolutionTemplatesItem, + >, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was last modified (ISO 8601). + pub updated_at: Option>, + /// `true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows. + pub upgrade_available: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionSolutionOrgLogo { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionSolutionTemplatesItemDetailsInvokeContractParticipantsItem +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Workflow-authored explanation of the slot's role. `null` when the workflow declares none. + pub description: Option, + /// The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking. + pub name: String, + /// Whether the workflow requires this slot to be filled for the run to complete its embedded stages. + pub required: bool, + #[serde(rename = "type")] + /// The kind of principal the slot accepts. Currently always `"agent_user"` — the value supplied at invoke is an agent ID (`agi_...`). + pub type_: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionSolutionTemplatesItemDetailsInvokeContractPrefills +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected. + pub payload: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionSolutionTemplatesItemDetailsInvokeContract { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured. + pub input_schema: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs. + pub participants: Option>, + /// Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected. + pub prefills: GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionSolutionTemplatesItemDetailsInvokeContractPrefills, +} + +/// Contract-defined values for GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionSolutionTemplatesItemDetailsType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionSolutionTemplatesItemDetailsType +{ + /// The automation wire value. + #[serde(rename = "automation")] + Automation, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionSolutionTemplatesItemDetails { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Automation execution type (`invoked`, `scheduled`, or `trigger`). + pub automation_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning. + pub invoke_contract: Option, + #[serde(rename = "type")] + /// Template-details discriminator. Always `automation` for this variant. + pub type_: GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionSolutionTemplatesItemDetailsType, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionSolutionTemplatesItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details. + pub details: Option< + GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionSolutionTemplatesItemDetails, + >, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`. + pub display_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template config ID (`cfg_...`). `null` for inline-only templates. + pub id: Option, + /// Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lookup key stamped on the template config at import time. `null` when no lookup key was assigned. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable virtual path assigned to the template config. `null` when no virtual path was set. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionSolution { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none. + pub category_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was first imported (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none. + pub events: Option>, + /// Solution config ID (`cfg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only. + pub image_url: Option, + /// Resource type. Always `"Solution"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise. + pub latest_solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise. + pub latest_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing display name declared in the Solution body. `null` when the Solution body does not set one. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo. + pub org_logo: + Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve. + pub org_slug: Option, + /// Owner scopes this Solution appears under. Members: `"system"` (app-level system scope) and/or `"org"` (viewer's org scope). + pub owners: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only. + pub screenshot_urls: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it. + pub solution_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Semver string declared in the Solution body (e.g. `"1.2.0"`). `null` when the body does not declare a version. + pub solution_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Freeform tag keys declared in the Solution body. An empty array when the body declares none. + pub tag_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Wrapped template kind — `"AgentTemplate"`, `"AutomationTemplate"`, `"AgentRoutineTemplate"`, `"AgentToolTemplate"`, `"AgentComputerTemplate"`, or `"SolutionTemplateRef"` for ref-mode bundles. + pub template_kind: Option, + /// Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references. + pub templates: + Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was last modified (ISO 8601). + pub updated_at: Option>, + /// `true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows. + pub upgrade_available: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionTemplate { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this template config was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Description of the template from the config body. `null` if the current version has no `description` field. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name from the config body. `null` if the current version has no `display_name` field. + pub display_name: Option, + /// Template config ID (`cfg_...`). + pub id: String, + /// Config kind identifier for this template (e.g. `"agent_tool_template"`). + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable lookup key assigned to this template config. `null` if no lookup key is set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template name as stored in the config body. `null` if the current version has no `name` field. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this template config was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Virtual filesystem path for this template config. `null` if not set. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolution { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now. + pub current_solution: + Option, + /// Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution. + pub solution: GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionSolution, + /// Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from. + pub template: GetApiV1TeamsTeamMembersResponseDataItemAgentSourceSolutionTemplate, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemAgent { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the application that owns this agent (`dap_...`). + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the agent was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `"claude-3-7-sonnet-latest"`). + pub default_model: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of what the agent does. `null` if not set. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address provisioned for this agent. `null` if email delivery is not configured. + pub email: Option, + /// Agent ID (`agi_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// System-level identity prompt that shapes the agent's persona and behavior. + pub identity: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents. + pub last_applied_template_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable, user-defined identifier for this agent within the application. Unique per app. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the agent. Not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name for the agent. `null` if not set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name). + pub originator: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Phone number provisioned for this agent. `null` if SMS is not configured. + pub phone_number: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints. + pub source_solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`). + pub template_upgrade_available: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the agent was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped. + pub user: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItemUser { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the user. `null` if not set. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app. + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the user's app. `null` when the app association was not preloaded by the caller. + pub app_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address of the user. + pub email: Option, + /// User ID (`usr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` if this account is an internal system user rather than a human. System users are created automatically by the platform. + pub is_system_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the user. Defaults to an empty object. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full display name of the user. `null` if the user has not set a name. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Role of the user within their organization. One of `"admin"`, `"member"`, or `"viewer"`. `null` when the user is not a member of any organization. + pub org_role: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller. + pub org_slug: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller. + pub sandbox_name: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The agent associated with this membership, as an expanded agent object. `null` when the member is a user, the type is unknown, or the association is not preloaded. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this membership record was created (ISO 8601). + pub created_at: Option>, + /// Team membership ID (`tmb_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the principal joined the team (ISO 8601). + pub joined_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to this membership record. `null` if no metadata has been set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the member, derived from the associated user or agent. `null` if the principal is unknown. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture of the member, derived from the associated user or agent. `null` if not set or principal is unknown. + pub profile_picture: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The member's role within the team. One of `"owner"`, `"admin"`, or `"member"`. + pub role: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The team this membership belongs to, as an expanded team object. `null` when the team association is not preloaded. + pub team: Option>, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved principal type. One of `"user"`, `"agent"`, or `"unknown"` when the principal cannot be determined. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this membership record was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The user associated with this membership, as an expanded user object. `null` when the member is an agent, the type is unknown, or the association is not preloaded. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamMembersResponse { + /// Array of team membership objects, including both user and agent members. + pub data: Vec, +} + +/// Adds a user or agent as a member of the specified team and returns the new +/// membership with HTTP 201. Provide exactly one of `user` or `agent` — supplying +/// both or neither returns a 400 error. +/// +/// The caller must have permission to manage the team. When an `app` is provided, +/// the request is scoped to that app and the caller must hold a valid app-scoped +/// token. The default role is `"member"` when `role` is omitted. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsTeamMembersInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID (`agt_...`) to add as a member. Provide exactly one of `user` or `agent`. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Role to assign. One of `"owner"`, `"admin"`, or `"member"`. Defaults to `"member"` when omitted. + pub role: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) to add as a member. Provide exactly one of `user` or `agent`. + pub user: Option, +} + +/// Changes the role of an existing user member on the specified team. Returns the +/// updated membership on success. +/// +/// Only user memberships are supported by this endpoint. Attempting to update an +/// agent membership returns 404. To change an agent's role, remove the existing +/// membership and re-add the agent with the desired role. +/// +/// The caller must have permission to modify the team. You cannot change a member's +/// role across organization boundaries. Demoting the last owner of a team returns +/// 409. An invalid `role` value returns 422. When `app` is provided, the request +/// is scoped to that app and requires a valid app-scoped token. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PatchApiV1TeamsTeamMembersUserInput { + /// New role to assign. One of `"owner"`, `"admin"`, or `"member"`. + pub role: String, +} + +/// Query parameters for get_api_v1_teams__team_tasks. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) for user-scoped tasks. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional organization (`org_...`) for developer and server-to-server calls. When omitted, the org is taken from the owner principal (team, user, or agent). When set, it must match that principal's org; pass null for an owner outside an organization. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter tasks by status. One of `"open"`, `"in_progress"`, or `"done"`. Omit to return tasks in all statuses. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter tasks assigned to a specific user. Provide the user's public ID (`usr_...`). + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter tasks assigned to a specific agent. Provide the agent's public ID (`agi_...`). + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter tasks by priority, from 0 (highest) to 4 (lowest). + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only tasks carrying this tag (matched against the canonical lowercase form). + pub tag: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only subtasks of the given task (`tsk_...`), or pass `none` to return only top-level tasks. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to tasks whose name or description contains this string. + pub search: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sort key. One of `"created"` (default — most recently created first), `"due_date"` (soonest due first; tasks without a due date always sort last), or `"priority"` (most urgent first). Ties break by most recently created. + pub sort: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sort direction, `"asc"` or `"desc"`. Defaults to `"desc"` for `created` and `"asc"` for `due_date` and `priority`. + pub order: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only tasks with a due date strictly before this ISO 8601 datetime (`2026-08-01T00:00:00Z`) or date (`2026-08-01`, meaning midnight UTC). Tasks without a due date are excluded. + pub due_before: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only tasks with a due date strictly after this ISO 8601 datetime or date. Tasks without a due date are excluded. + pub due_after: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, return only overdue tasks: a due date before the current UTC day and a status other than `"done"`. A task due today is not overdue. + pub overdue: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When true, return only open tasks with no unfinished blockers and no active session lease. This is a projection snapshot; claim a lease before starting work. + pub ready: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of tasks to return. Capped at 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the previous page. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksResponseDataItemCreatedByActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksResponseDataItemCreatedByActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksResponseDataItemCurrentLease { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the coding session. + pub harness: String, + /// Display name supplied by the coding session that holds the lease. + pub session_name: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksResponseDataItemOwnerActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksResponseDataItemOwnerActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind. + pub blocked_by_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open. + pub closed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of comments posted on this task. + pub comments_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted). + pub created_by_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted. + pub created_by_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted. + pub created_by_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included. + pub current_lease: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Long-form description or notes for the task. `null` if no description has been provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). `null` if no due date is set. + pub due_date: Option>, + /// Task ID (`tsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read. + pub is_blocked: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set. + pub metadata: Option>, + /// Human-readable title of the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted). + pub owner_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment. + pub sandbox: Option, + /// Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks. + pub subtasks_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + /// Array of task objects matching the requested filters. + pub data: Vec, + /// API field. + pub has_more: bool, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsTeamTasksInputTask { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional long-form description or notes for the task. Supports plain text. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). Omit to create the task without a due date. + pub due_date: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of named URLs or references associated with the task (e.g. external ticket links). + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map for storing application-specific data alongside the task. Omit to create the task with no metadata. + pub metadata: Option>, + /// Human-readable title for the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent to assign as owner (`agi_...`). Mutually exclusive with `owner_user`; omit to leave the task unassigned. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user to assign as owner (`usr_...`). Mutually exclusive with `owner_agent`; omit to leave the task unassigned. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Create this task as a subtask of an existing top-level task (`tsk_...`). Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when omitted. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Initial status for the task. One of `"open"`, `"in_progress"`, or `"done"`. Defaults to `"open"` when omitted. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering (max 20, each up to 40 characters). Stored canonically: lowercase, trimmed, de-duplicated. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Bind the task to a thread (`thr_...`) owned by the same team or user as the task. A bound task appears in that thread's task scope, exactly like a task filed from inside the conversation. Omit for a task not tied to a conversation. + pub thread: Option, +} + +/// Creates a new task owned by the specified user or team and returns the full +/// task object. User-authenticated calls are attributed to the authenticated +/// user or agent. App-scoped developer and server-to-server callers must provide +/// the task's explicit `org` scope and an explicit `user` or `agent` actor for +/// team tasks; a user-owned task reuses the user in the route unless an explicit +/// agent is supplied. Every referenced principal is validated against the app, +/// owner, and team membership before creation. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsTeamTasksInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit acting agent (`agi_...`) for a developer or server-to-server call. Mutually exclusive with an acting `user`; the agent must belong to the task owner. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit organization (`org_...`) for developer and server-to-server calls. Pass null when the owner is not organization-scoped. The value must match the selected user or team. + pub org: Option, + /// Attributes for the task to create. `name` is required; all other fields are optional. + pub task: PostApiV1TeamsTeamTasksInputTask, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`). On a user route this is the task owner and creator; on a team route it is the explicit acting user for a developer or server-to-server call. + pub user: Option, +} + +/// Query parameters for get_api_v1_teams__team_tasks_blocker_cycles. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksBlockerCyclesParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) owning the tasks. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional organization context for privileged callers. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum cycle components to return. Defaults to 50; maximum is 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the preceding page. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksBlockerCyclesResponseDataItemTasksItemCreatedByActorProfilePicture +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksBlockerCyclesResponseDataItemTasksItemCreatedByActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option< + GetApiV1TeamsTeamTasksBlockerCyclesResponseDataItemTasksItemCreatedByActorProfilePicture, + >, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksBlockerCyclesResponseDataItemTasksItemCurrentLease { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the coding session. + pub harness: String, + /// Display name supplied by the coding session that holds the lease. + pub session_name: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksBlockerCyclesResponseDataItemTasksItemOwnerActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksBlockerCyclesResponseDataItemTasksItemOwnerActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option< + GetApiV1TeamsTeamTasksBlockerCyclesResponseDataItemTasksItemOwnerActorProfilePicture, + >, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksBlockerCyclesResponseDataItemTasksItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind. + pub blocked_by_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open. + pub closed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of comments posted on this task. + pub comments_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted). + pub created_by_actor: + Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted. + pub created_by_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted. + pub created_by_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included. + pub current_lease: + Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Long-form description or notes for the task. `null` if no description has been provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). `null` if no due date is set. + pub due_date: Option>, + /// Task ID (`tsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read. + pub is_blocked: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set. + pub metadata: Option>, + /// Human-readable title of the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted). + pub owner_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment. + pub sandbox: Option, + /// Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks. + pub subtasks_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team. + pub user: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksBlockerCyclesResponseDataItem { + /// Every unfinished task in this cyclic blocker component. + pub tasks: Vec, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksBlockerCyclesResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + /// API field. + pub data: Vec, + /// API field. + pub has_more: bool, +} + +/// Query parameters for get_api_v1_teams__team_tasks_metrics. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksMetricsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// UTC-day window. One of 7, 30, 90, or 365; defaults to 30. + pub days: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksMetricsResponse { + /// API field. + pub completed: i64, + /// API field. + pub created: i64, + /// API field. + pub days: i64, + /// API field. + pub end_at: chrono::DateTime, + /// API field. + pub open: i64, + /// Zero-filled UTC-day buckets with `date`, end-of-day `open`, `created`, and `completed`. + pub series: Vec>, + /// API field. + pub start_at: chrono::DateTime, +} + +/// Query parameters for get_api_v1_teams__team_tasks_ready. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksReadyParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) owning the tasks. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional organization context for privileged callers. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Include blocked and actively leased open tasks with exclusion reasons. + pub explain: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Only include tasks assigned to the authenticated user. + pub assigned_to_me: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of readiness entries to return. Capped at 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the previous page. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksReadyResponseDataItemTaskCreatedByActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksReadyResponseDataItemTaskCreatedByActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksReadyResponseDataItemTaskCurrentLease { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the coding session. + pub harness: String, + /// Display name supplied by the coding session that holds the lease. + pub session_name: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksReadyResponseDataItemTaskOwnerActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksReadyResponseDataItemTaskOwnerActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksReadyResponseDataItemTask { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind. + pub blocked_by_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open. + pub closed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of comments posted on this task. + pub comments_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted). + pub created_by_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted. + pub created_by_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted. + pub created_by_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included. + pub current_lease: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Long-form description or notes for the task. `null` if no description has been provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). `null` if no due date is set. + pub due_date: Option>, + /// Task ID (`tsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read. + pub is_blocked: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set. + pub metadata: Option>, + /// Human-readable title of the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted). + pub owner_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment. + pub sandbox: Option, + /// Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks. + pub subtasks_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team. + pub user: Option, +} + +/// Contract-defined values for GetApiV1TeamsTeamTasksReadyResponseDataItemReadiness. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1TeamsTeamTasksReadyResponseDataItemReadiness { + /// The ready wire value. + #[serde(rename = "ready")] + Ready, + /// The blocked wire value. + #[serde(rename = "blocked")] + Blocked, + /// The leased wire value. + #[serde(rename = "leased")] + Leased, +} + +/// Contract-defined values for GetApiV1TeamsTeamTasksReadyResponseDataItemReason. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1TeamsTeamTasksReadyResponseDataItemReason { + /// The open_blockers wire value. + #[serde(rename = "open_blockers")] + OpenBlockers, + /// The active_lease wire value. + #[serde(rename = "active_lease")] + ActiveLease, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksReadyResponseDataItem { + /// One of `ready`, `blocked`, or `leased`. + pub readiness: GetApiV1TeamsTeamTasksReadyResponseDataItemReadiness, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable exclusion reason: `open_blockers` or `active_lease`; omitted when ready. + pub reason: Option, + /// The task evaluated for readiness. + pub task: GetApiV1TeamsTeamTasksReadyResponseDataItemTask, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksReadyResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + /// Always false because projections can lag writes and a later claim can race this read. + pub authoritative: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + /// API field. + pub data: Vec, + /// API field. + pub has_more: bool, +} + +/// Query parameters for get_api_v1_teams__team_tasks_search. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksSearchParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) whose tasks are searched. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional organization (`org_...`) for developer and server-to-server calls. When omitted, the org is taken from the owner principal (team, user, or agent). When set, it must match that principal's org; pass null for an owner outside an organization. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full-text search query matched against task names and descriptions. Takes precedence over `query` when both are provided. + pub q: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Alias for `q`. Use `q` when possible; this parameter exists for compatibility. + pub query: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results by status. One of `"open"`, `"in_progress"`, or `"done"`. Omit to include all statuses. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to tasks assigned to the user with this public ID (`usr_...`). + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to tasks assigned to the agent with this public ID (`agi_...`). + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results by priority, from 0 (highest) to 4 (lowest). + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only tasks carrying this tag (matched against the canonical lowercase form). + pub tag: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only subtasks of the given task (`tsk_...`), or pass `none` to return only top-level tasks. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of tasks to return. Capped at 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the previous page. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksSearchResponseDataItemCreatedByActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksSearchResponseDataItemCreatedByActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksSearchResponseDataItemCurrentLease { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the coding session. + pub harness: String, + /// Display name supplied by the coding session that holds the lease. + pub session_name: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksSearchResponseDataItemOwnerActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksSearchResponseDataItemOwnerActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksSearchResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind. + pub blocked_by_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open. + pub closed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of comments posted on this task. + pub comments_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted). + pub created_by_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted. + pub created_by_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted. + pub created_by_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included. + pub current_lease: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Long-form description or notes for the task. `null` if no description has been provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). `null` if no due date is set. + pub due_date: Option>, + /// Task ID (`tsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read. + pub is_blocked: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set. + pub metadata: Option>, + /// Human-readable title of the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted). + pub owner_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment. + pub sandbox: Option, + /// Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks. + pub subtasks_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamTasksSearchResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + /// Array of task objects matching the query and filters. + pub data: Vec, + /// API field. + pub has_more: bool, + /// API field. + pub query: String, +} + +/// Query parameters for get_api_v1_teams__team_threads. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional: only return threads tagged with at least one of these tags (OR-match). Repeated query params, e.g. `?tags[]=blocked&tags[]=needs-review`. + pub tags: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParentMessageAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParentMessageAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParentMessageAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParentMessageAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParentMessageActorsItemProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParentMessageActorsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParentMessageAttachmentsItemImageSource { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParentMessageAttachmentsItemVariantsItemImageSource +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParentMessageAttachmentsItemVariantsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of this variant's file (e.g., `"image/jpeg"`, `"video/mp4"`). `null` if the file is not loaded. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this variant was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file that backs this variant (`fil_...`). + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the uploaded file for this variant. `null` if the file is not loaded. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of this variant in pixels. `null` if not recorded. + pub height: Option, + /// Media variant ID (`mvr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types. + pub image_source: Option< + GetApiV1TeamsTeamThreadsResponseDataItemParentMessageAttachmentsItemVariantsItemImageSource, + >, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this variant was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed download URL for this variant, resolved at request time. `null` if the file is unavailable. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier for this variant's processing tier. Common values include `"original"` (the unmodified upload) and `"thumbnail"` (a resized preview). + pub variant_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of this variant in pixels. `null` if not recorded. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParentMessageAttachmentsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the attached file, e.g. `"image/png"` or `"application/pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the attached file, e.g. `"report.pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height in pixels of the media item. Present on `media` type only. `null` otherwise. + pub height: Option, + /// Unique identifier for this attachment within the message. + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise. + pub image_height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise. + pub image_source: + Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise. + pub image_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise. + pub image_width: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The media category, e.g. `"video"` or `"audio"`. Present on `media` type only. `null` otherwise. + pub media_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the media item. Present on `media` type only. `null` otherwise. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types. + pub object: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types. + pub title: Option, + #[serde(rename = "type")] + /// The attachment type. One of `"file"`, `"scraped_link"`, `"artifact"`, `"task"`, `"media"`, `"action"`, or `"chart"`. Determines which additional fields are present. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise. + pub variants: Option< + Vec, + >, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise. + pub version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width in pixels of the media item. Present on `media` type only. `null` otherwise. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParentMessageReactionsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Type-specific reaction data. For `"emoji_reaction"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `"👍"`). + pub payload: Option>, + #[serde(rename = "type")] + /// Reaction type identifier. Currently always `"emoji_reaction"` for emoji-based reactions. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Public ID of the user who added the reaction (`usr_...`). + pub user: Option, +} + +/// Contract-defined values for GetApiV1TeamsTeamThreadsResponseDataItemParentMessageAgentMode. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1TeamsTeamThreadsResponseDataItemParentMessageAgentMode { + /// The cli wire value. + #[serde(rename = "cli")] + Cli, + /// The embedded wire value. + #[serde(rename = "embedded")] + Embedded, +} + +/// Contract-defined values for GetApiV1TeamsTeamThreadsResponseDataItemParentMessageVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1TeamsTeamThreadsResponseDataItemParentMessageVisibility { + /// The default wire value. + #[serde(rename = "default")] + Default, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParentMessage { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry. + pub actors: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path. + pub agent_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments. + pub attachments: + Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread. + pub branched_thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Text content of the message. `null` for messages that contain only attachments. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the message was posted (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this message has at least one reply. Only present when explicitly requested or computed by the server. + pub has_replies: Option, + /// Message ID (`msg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one. + pub idempotency_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages. + pub is_deleted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users. + pub legacy_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization that owns this message (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded. + pub reactions: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display hint for how the message should be rendered. One of `"reply"`, `"direct"`, or `"inline"`. `null` for user-authored messages, which are always rendered as standard replies. + pub rendering_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message. + pub replies: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response. + pub replies_after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response. + pub replies_before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of direct replies to this message. Only present when explicitly requested or computed by the server. + pub reply_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded. + pub reply_to: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages. + pub root_message_id: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread. + pub thread: Option, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees. + pub visibility: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipantsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the user. `null` if not set. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app. + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the user's app. `null` when the app association was not preloaded by the caller. + pub app_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address of the user. + pub email: Option, + /// User ID (`usr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` if this account is an internal system user rather than a human. System users are created automatically by the platform. + pub is_system_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the user. Defaults to an empty object. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full display name of the user. `null` if the user has not set a name. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Role of the user within their organization. One of `"admin"`, `"member"`, or `"viewer"`. `null` when the user is not a member of any organization. + pub org_role: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller. + pub org_slug: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller. + pub sandbox_name: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: + Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: + Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionOrgLogo +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsInvokeContractParticipantsItem +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Workflow-authored explanation of the slot's role. `null` when the workflow declares none. + pub description: Option, + /// The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking. + pub name: String, + /// Whether the workflow requires this slot to be filled for the run to complete its embedded stages. + pub required: bool, + #[serde(rename = "type")] + /// The kind of principal the slot accepts. Currently always `"agent_user"` — the value supplied at invoke is an agent ID (`agi_...`). + pub type_: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsInvokeContractPrefills +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected. + pub payload: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsInvokeContract { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured. + pub input_schema: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs. + pub participants: Option>, + /// Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected. + pub prefills: GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsInvokeContractPrefills, +} + +/// Contract-defined values for GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsType +{ + /// The automation wire value. + #[serde(rename = "automation")] + Automation, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetails { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Automation execution type (`invoked`, `scheduled`, or `trigger`). + pub automation_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning. + pub invoke_contract: Option, + #[serde(rename = "type")] + /// Template-details discriminator. Always `automation` for this variant. + pub type_: GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsType, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details. + pub details: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`. + pub display_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template config ID (`cfg_...`). `null` for inline-only templates. + pub id: Option, + /// Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lookup key stamped on the template config at import time. `null` when no lookup key was assigned. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable virtual path assigned to the template config. `null` when no virtual path was set. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolution { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none. + pub category_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was first imported (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none. + pub events: Option>, + /// Solution config ID (`cfg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only. + pub image_url: Option, + /// Resource type. Always `"Solution"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise. + pub latest_solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise. + pub latest_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing display name declared in the Solution body. `null` when the Solution body does not set one. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo. + pub org_logo: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve. + pub org_slug: Option, + /// Owner scopes this Solution appears under. Members: `"system"` (app-level system scope) and/or `"org"` (viewer's org scope). + pub owners: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only. + pub screenshot_urls: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it. + pub solution_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Semver string declared in the Solution body (e.g. `"1.2.0"`). `null` when the body does not declare a version. + pub solution_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Freeform tag keys declared in the Solution body. An empty array when the body declares none. + pub tag_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Wrapped template kind — `"AgentTemplate"`, `"AutomationTemplate"`, `"AgentRoutineTemplate"`, `"AgentToolTemplate"`, `"AgentComputerTemplate"`, or `"SolutionTemplateRef"` for ref-mode bundles. + pub template_kind: Option, + /// Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references. + pub templates: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was last modified (ISO 8601). + pub updated_at: Option>, + /// `true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows. + pub upgrade_available: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionOrgLogo +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsInvokeContractParticipantsItem +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Workflow-authored explanation of the slot's role. `null` when the workflow declares none. + pub description: Option, + /// The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking. + pub name: String, + /// Whether the workflow requires this slot to be filled for the run to complete its embedded stages. + pub required: bool, + #[serde(rename = "type")] + /// The kind of principal the slot accepts. Currently always `"agent_user"` — the value supplied at invoke is an agent ID (`agi_...`). + pub type_: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsInvokeContractPrefills +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected. + pub payload: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsInvokeContract { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured. + pub input_schema: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs. + pub participants: Option>, + /// Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected. + pub prefills: GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsInvokeContractPrefills, +} + +/// Contract-defined values for GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsType +{ + /// The automation wire value. + #[serde(rename = "automation")] + Automation, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetails { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Automation execution type (`invoked`, `scheduled`, or `trigger`). + pub automation_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning. + pub invoke_contract: Option, + #[serde(rename = "type")] + /// Template-details discriminator. Always `automation` for this variant. + pub type_: GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsType, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details. + pub details: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`. + pub display_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template config ID (`cfg_...`). `null` for inline-only templates. + pub id: Option, + /// Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lookup key stamped on the template config at import time. `null` when no lookup key was assigned. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable virtual path assigned to the template config. `null` when no virtual path was set. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolution { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none. + pub category_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was first imported (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none. + pub events: Option>, + /// Solution config ID (`cfg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only. + pub image_url: Option, + /// Resource type. Always `"Solution"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise. + pub latest_solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise. + pub latest_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing display name declared in the Solution body. `null` when the Solution body does not set one. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo. + pub org_logo: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve. + pub org_slug: Option, + /// Owner scopes this Solution appears under. Members: `"system"` (app-level system scope) and/or `"org"` (viewer's org scope). + pub owners: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only. + pub screenshot_urls: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it. + pub solution_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Semver string declared in the Solution body (e.g. `"1.2.0"`). `null` when the body does not declare a version. + pub solution_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Freeform tag keys declared in the Solution body. An empty array when the body declares none. + pub tag_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Wrapped template kind — `"AgentTemplate"`, `"AutomationTemplate"`, `"AgentRoutineTemplate"`, `"AgentToolTemplate"`, `"AgentComputerTemplate"`, or `"SolutionTemplateRef"` for ref-mode bundles. + pub template_kind: Option, + /// Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references. + pub templates: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was last modified (ISO 8601). + pub updated_at: Option>, + /// `true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows. + pub upgrade_available: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionTemplate { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this template config was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Description of the template from the config body. `null` if the current version has no `description` field. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name from the config body. `null` if the current version has no `display_name` field. + pub display_name: Option, + /// Template config ID (`cfg_...`). + pub id: String, + /// Config kind identifier for this template (e.g. `"agent_tool_template"`). + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable lookup key assigned to this template config. `null` if no lookup key is set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template name as stored in the config body. `null` if the current version has no `name` field. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this template config was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Virtual filesystem path for this template config. `null` if not set. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolution { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now. + pub current_solution: Option, + /// Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution. + pub solution: GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolution, + /// Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from. + pub template: GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItemSourceSolutionTemplate, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemParticipatingAgentsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the application that owns this agent (`dap_...`). + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the agent was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `"claude-3-7-sonnet-latest"`). + pub default_model: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of what the agent does. `null` if not set. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address provisioned for this agent. `null` if email delivery is not configured. + pub email: Option, + /// Agent ID (`agi_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// System-level identity prompt that shapes the agent's persona and behavior. + pub identity: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents. + pub last_applied_template_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable, user-defined identifier for this agent within the application. Unique per app. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the agent. Not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name for the agent. `null` if not set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name). + pub originator: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Phone number provisioned for this agent. `null` if SMS is not configured. + pub phone_number: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints. + pub source_solution: + Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`). + pub template_upgrade_available: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the agent was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped. + pub user: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItemSettings { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured. + pub agent_enabled: Option, +} + +/// Contract-defined alternatives for GetApiV1TeamsTeamThreadsResponseDataItemCreator. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetApiV1TeamsTeamThreadsResponseDataItemCreator { + /// Variant1 union variant. + Variant1(String), + /// Variant2 union variant. + Variant2(Value), +} + +/// Contract-defined values for GetApiV1TeamsTeamThreadsResponseDataItemVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1TeamsTeamThreadsResponseDataItemVisibility { + /// The team wire value. + #[serde(rename = "team")] + Team, + /// The restricted wire value. + #[serde(rename = "restricted")] + Restricted, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this thread (`agt_...`). `null` for user-owned or team-owned threads. + pub agent_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the thread was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User who created this thread. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if the creator is unknown. + pub creator: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional description or purpose statement for the thread. `null` if not set. + pub description: Option, + /// Thread ID (`thr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this thread operates as a channel — a multi-member broadcast-style conversation. + pub is_channel: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this is the default thread for its owner. Each user or team has at most one default thread. + pub is_default: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this thread is ephemeral and may be deleted automatically after a period of inactivity or when its TTL expires. + pub is_transient: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this thread is hidden from public discovery. Unlisted threads are accessible only to direct participants. + pub is_unlisted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Application-defined stable key that uniquely identifies the thread within its scope. Useful for idempotent creation. `null` if not set. + pub key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Thread subtype: `"standard"` for ordinary threads, `"slack_mirror"` for the membership-strict mirror of a Slack channel, `"slashwork_mirror"` for the membership-strict mirror of a Slashwork group. Read-only — derived server-side at creation, never accepted from params. + pub kind: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the most recent message was posted in this thread, falling back to the thread's creation time if it has no messages. Always populated on thread list endpoints (which order by it, after default threads); `null` on endpoints that don't compute activity enrichment. + pub last_activity: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Single-line snippet of the most recent message's text content (first non-empty line, truncated to 140 characters). Populated on thread list endpoints alongside `last_activity`; `null` when the thread has no messages, the latest message has no text content (e.g. attachment-only), or the endpoint doesn't compute activity enrichment. + pub last_message_preview: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the sender of the most recent message — the same message `last_message_preview` snippets. Populated on thread list endpoints; `null` when the thread has no messages or the endpoint doesn't compute activity enrichment. + pub last_message_sender: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the thread. Shape is application-defined; `null` if no metadata has been set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether the authenticated user has muted notifications for this thread. `true` suppresses all notification delivery. + pub muted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this thread belongs to (`org_...`). `null` for threads outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The message that spawned this thread as a sub-thread. `null` for top-level threads. + pub parent_message: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of participant user IDs (`usr_...`) who are members of this thread. + pub participant: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Expanded participant user objects for each member of this thread. Populated only when the association is loaded. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifiers for all participants currently active in this thread. Present only when actor enrichment is requested. + pub participating_actor: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Expanded agent objects for all agents participating in this thread. Present only when agent enrichment is requested. + pub participating_agents: + Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The authenticated user's membership role in this thread, e.g. `"owner"`, `"member"`, or `"viewer"`. `null` if the user is not a member. + pub role: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this thread is scoped to (`dsb_...`). `null` for production threads. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Per-thread configuration settings controlling AI agent behavior for this thread. + pub settings: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL-safe slug for the thread, used in human-readable permalinks. `null` if not assigned. + pub slug: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Threads that are nested under this thread as replies to a parent message. Present only when sub-thread enrichment is requested. + pub sub_threads: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Status tags on the thread (e.g. `"blocked"`, `"needs-review"`). Edited by any thread participant via the `/threads/:thread/tags` endpoints and filterable on the thread list endpoints. Empty array if none set. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this thread (`team_...`). `null` for user-owned or agent-owned threads. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable name of the thread. `null` if no title has been set. + pub title: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Time-to-live in seconds after which the thread may be automatically cleaned up. `null` if the thread does not expire. + pub ttl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of messages in this thread that the authenticated user has not yet read. Present only when read-state enrichment is requested. + pub unread_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the thread was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who owns this thread (`usr_...`). `null` for team-owned or agent-owned threads. + pub user: Option, + /// Who can read the thread: `team` for every owning-team member, `restricted` for team-readable threads with an explicit roster, or `private` for roster-only access. + pub visibility: GetApiV1TeamsTeamThreadsResponseDataItemVisibility, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsResponse { + /// Array of thread objects belonging to the team. + pub data: Vec, +} + +/// Contract-defined values for PostApiV1TeamsTeamThreadsInputThreadMembersItemType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum PostApiV1TeamsTeamThreadsInputThreadMembersItemType { + /// The user wire value. + #[serde(rename = "user")] + User, + /// The agent wire value. + #[serde(rename = "agent")] + Agent, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsTeamThreadsInputThreadMembersItem { + /// Public user (`usr_...`) or agent (`agt_...`) ID matching `type`. + pub id: String, + #[serde(rename = "type")] + /// Member kind. Use `user` for a user ID or `agent` for an agent ID. + pub type_: PostApiV1TeamsTeamThreadsInputThreadMembersItemType, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsTeamThreadsInputThreadProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Base64-encoded image bytes. + pub data: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the uploaded image, used for display and content-type inference. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. + pub mime_type: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsTeamThreadsInputThreadSettings { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured. + pub agent_enabled: Option, +} + +/// Contract-defined values for PostApiV1TeamsTeamThreadsInputThreadVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum PostApiV1TeamsTeamThreadsInputThreadVisibility { + /// The team wire value. + #[serde(rename = "team")] + Team, + /// The restricted wire value. + #[serde(rename = "restricted")] + Restricted, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsTeamThreadsInputThread { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, provisions a legacy chat agent alongside the thread. Only needed for integrations that depend on the pre-v2 agent model. + pub create_legacy_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional longer description of the thread's purpose. `null` if not provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, the thread is hidden from the default thread list and accessible only by direct link or ID. + pub is_unlisted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Client-assigned unique key for idempotent creation or later lookup. Must be unique within the owning organization. + pub key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Users and agents to add atomically when the thread is created. Each target must pass the same authorization rules as a post-creation member add. Slack mirror threads reject non-empty caller-supplied rosters because their membership is sync-owned. + pub members: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value pairs stored alongside the thread. Values must be strings or numbers. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, push and in-app notifications for this thread are suppressed for the creating user. + pub muted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization to create the thread under. Defaults to the authenticated user's primary organization when omitted. + pub org_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional profile image for the thread, provided as a base64-encoded payload. + pub profile_picture: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Configuration overrides for the thread, such as AI model selection and context window settings. + pub settings: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional URL-safe identifier. Derived from the title when omitted and unique within the thread owner. + pub slug: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name for the thread. `null` if omitted, which causes the thread to be untitled. + pub title: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Thread visibility. A team-owned thread with members must explicitly use `restricted` or `private`. User- and agent-owned threads with members default to `private` and reject every other value. + pub visibility: Option, +} + +/// Creates a new thread owned by the specified team. The authenticated caller must +/// have access to the team; requests from callers without team access are rejected +/// with 404. +/// +/// If a `profile_picture` is provided in the thread params, it must be +/// base64-encoded image data. The image is uploaded and associated with the thread +/// before creation completes. Omit `profile_picture` to skip this step. +/// +/// By default the platform sends an automatic welcome message into the new thread. +/// Pass `skip_welcome_message: true` to suppress this behavior, for example when +/// creating threads programmatically in bulk or seeding test data. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1TeamsTeamThreadsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, suppresses the automatic welcome message that is otherwise sent into the thread on creation. Defaults to `false`. + pub skip_welcome_message: Option, + /// Attributes for the new thread. See ThreadCreateParams for available fields. + pub thread: PostApiV1TeamsTeamThreadsInputThread, +} + +/// Query parameters for get_api_v1_teams__team_threads_metrics. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsMetricsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// UTC-day window. One of 7, 30, 90, or 365; defaults to 30. + pub days: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1TeamsTeamThreadsMetricsResponse { + /// API field. + pub days: i64, + /// API field. + pub end_at: chrono::DateTime, + /// API field. + pub opened: i64, + /// API field. + pub start_at: chrono::DateTime, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1ThreadMessagesMessageInputAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1ThreadMessagesMessageInputAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1ThreadMessagesMessageInputAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1ThreadMessagesMessageInputAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Contract-defined values for PutApiV1ThreadMessagesMessageInputVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum PutApiV1ThreadMessagesMessageInputVisibility { + /// The default wire value. + #[serde(rename = "default")] + Default, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// Edits an existing thread message and returns the updated message object. +/// +/// A regular user may only edit messages they authored. Service-to-service +/// callers with elevated (`all_powerful`) scope may edit any accessible message +/// without an ownership check. Returns `403 Forbidden` when the caller does not +/// own the message. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1ThreadMessagesMessageInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for a private message (replace or patch grants). Only valid when the message is already `private`. Omit to leave unchanged. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement text content for the message. Omit to leave the content unchanged. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement key-value metadata. Keys beginning with `sys:` are reserved and stripped. + pub metadata: Option>, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement client-defined classification. Free-form string up to 64 characters; platform-reserved values such as `system` are rejected. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Create-time message visibility. Supplying the existing value is harmless, but changing between `default` and `private` returns 422. + pub visibility: Option, +} + +/// Query parameters for get_api_v1_thread_messages__message_replies. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadMessagesMessageRepliesParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor. Returns replies created before this point. Obtain from `before_cursor` in a previous response. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor. Returns replies created after this point. Obtain from `after_cursor` in a previous response. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of replies to return per page. Defaults to 20. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, returns all replies in the nested reply tree (flattened). When `false` or omitted, returns only direct replies to the message. + pub tree: Option, +} + +/// Adds an emoji reaction to the specified thread message on behalf of the +/// authenticated user. If the user has already reacted to the message with the +/// same emoji, the request returns a 409 Conflict rather than creating a +/// duplicate. +/// +/// The authenticated user must have read access to the thread containing the +/// message. If the thread belongs to a team, the user must be a member of +/// that team. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ThreadMessagesMessageReactionsInput { + /// Emoji character or shortcode to add as a reaction, e.g. `"👍"` or `":thumbsup:"`. + pub emoji: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ThreadMessagesMessageReactionsResponseData { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the reaction was added (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Category of feedback. Currently `"emoji_reaction"` for emoji responses. + pub feedback_type: Option, + /// Reaction ID (`umf_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the message this reaction is attached to (`msg_...`). + pub message: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Structured data for the reaction. For `"emoji_reaction"` types, includes an `emoji` key with the Unicode emoji string. + pub payload: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the reaction was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who added the reaction (`usr_...`). + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ThreadMessagesMessageReactionsResponse { + /// Reaction object that was created. + pub data: PostApiV1ThreadMessagesMessageReactionsResponseData, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1ThreadsThreadInputProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Base64-encoded image payload. Must be a valid base64 string. + pub data: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the image, e.g. `"avatar.png"`. Used for storage metadata. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/jpeg"` or `"image/png"`. + pub mime_type: Option, +} + +/// Contract-defined values for PutApiV1ThreadsThreadInputVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum PutApiV1ThreadsThreadInputVisibility { + /// The private wire value. + #[serde(rename = "private")] + Private, + /// The restricted wire value. + #[serde(rename = "restricted")] + Restricted, + /// The team wire value. + #[serde(rename = "team")] + Team, +} + +/// Updates one or more mutable properties of the specified thread and returns +/// the full thread object with the applied changes. Only the fields you provide +/// are modified; omitted fields retain their current values. +/// +/// If `profile_picture` is supplied, the image is uploaded before the other +/// fields are saved, after all ordinary thread fields have passed validation. +/// Supplying invalid base64 picture data returns 422 and no other fields are +/// updated. +/// +/// Visibility can only widen: `private` may become `restricted` or `team`, and +/// `restricted` may become `team`. The authenticated viewer must have +/// permission to modify the thread. +/// +/// Mirror-thread titles, descriptions, and notification state remain editable +/// by privileged app viewers. Mirror metadata, visibility, and membership are +/// provider-managed and cannot be changed through this endpoint. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1ThreadsThreadInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional longer text describing the thread's purpose. Replaces the existing description when provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to store on the thread. Merged with or replaces existing metadata. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, suppresses notifications for new messages in this thread for the authenticated user. + pub muted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New profile picture for the thread. Provide all three inner fields to replace the existing image. + pub profile_picture: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name for the thread. Replaces the existing title when provided. + pub title: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Widen a team-owned thread: `private` may become `restricted` or `team`, and `restricted` may become `team`. Visibility cannot be narrowed. + pub visibility: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadAgentsResponse { + /// Array of agent objects for the thread. Each object includes `id`, `name`, `alias`, `profile_picture`, and `metadata`. Thread owners also receive an `agent_config` object with the agent's policy type and context configuration. + pub data: Vec>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadArtifactsResponseDataItemImageSource { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadArtifactsResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that produced this artifact (`agt_...`). `null` if not agent-produced. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the current version's file, e.g. `"text/csv"` or `"image/png"`. `null` if no file is attached. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the artifact was first created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the current (latest published) artifact version (`artv_...`). `null` if no version has been published. + pub current_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional longer description of the artifact's contents or purpose. `null` if not set. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Storage file ID for the current version (`fil_...`). `null` if no file is attached. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the current version's file, e.g. `"output.csv"`. `null` if no file is attached. + pub file_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short-lived signed URL for downloading the current version's file. `null` if no file is attached. + pub file_url: Option, + /// Artifact ID (`art_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Image source metadata for rendering the current version's file inline. Present only when `content_type` starts with `"image/"`. `null` otherwise. + pub image_source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable name for the artifact, e.g. `"Q2 Report"`. `null` if not set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this artifact belongs to (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the sandbox environment associated with this artifact. `null` if not sandbox-scoped. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this artifact (`tea_...`). `null` if not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread in which this artifact was created (`thr_...`). `null` if not thread-scoped. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the artifact record was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this artifact (`usr_...`). `null` if not user-scoped. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current version number of the artifact. Increments each time a new version is published. + pub version: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadArtifactsResponse { + /// Array of artifact objects produced during the thread's conversation. + pub data: Vec, +} + +/// Records that a user has read up to a specific message in the thread. Unread +/// indicators and badge counts are cleared up to the specified message. +/// +/// You must supply exactly one of `last_read_message` or `use_latest_message`. +/// Omitting both returns 400. If `use_latest_message` is `true` and the thread +/// has no messages, the request succeeds silently with no state change. +/// +/// For server-to-server (S2S) requests where no user identity is present in the +/// token, the `user` param is required to identify whose read state to update. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ThreadsThreadMarkReadInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message ID (`msg_...`) to record as the last read message. Mutually exclusive with `use_latest_message`. + pub last_read_message: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, marks the thread as read up to the latest message. Mutually exclusive with `last_read_message`. + pub use_latest_message: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) whose read state to update. Required for S2S requests; ignored when an authenticated user is present in the token. + pub user: Option, +} + +/// Contract-defined values for GetApiV1ThreadsThreadMessagesParamsDirection. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1ThreadsThreadMessagesParamsDirection { + /// The before wire value. + #[serde(rename = "before")] + Before, + /// The after wire value. + #[serde(rename = "after")] + After, + /// The around wire value. + #[serde(rename = "around")] + Around, +} + +/// Contract-defined values for GetApiV1ThreadsThreadMessagesParamsAnchorAgentMode. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1ThreadsThreadMessagesParamsAnchorAgentMode { + /// The cli wire value. + #[serde(rename = "cli")] + Cli, + /// The embedded wire value. + #[serde(rename = "embedded")] + Embedded, +} + +/// Query parameters for get_api_v1_threads__thread_messages. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned in a previous response's `before_cursor` field. When provided, returns messages immediately before that position. May be combined with `after_cursor` to bound a range. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned in a previous response's `after_cursor` field. When provided, returns messages immediately after that position. May be combined with `before_cursor` to bound a range. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Structured metadata filter expression. Only messages whose `metadata` object satisfies the expression are returned. The filter is applied before cursor pagination and anchored window limits. + pub metadata: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of messages to return per page. Defaults to 20; maximum is 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message ID (`msg_...`) to use as a window anchor, or `last_matching` to resolve the anchor from the latest message matching the anchor filters. Cannot be combined with `before_cursor` or `after_cursor`. + pub anchor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Window direction relative to `anchor`. `before` returns older messages, `after` returns newer messages, and `around` returns messages on both sides. Defaults to `after` when `anchor` is supplied. `direction=around` cannot be combined with an explicit `limit`; use `before_limit` and `after_limit`. + pub direction: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// For `direction=around`, maximum number of messages older than the anchor. Defaults to 20; maximum is 100. + pub before_limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// For `direction=around`, maximum number of messages newer than the anchor. Defaults to 20; maximum is 100. + pub after_limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether to include the anchor message in a window response. Defaults to `true` for `direction=around`; ignored for ordinary cursor pagination and one-sided windows. + pub include_anchor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `anchor=last_matching`, resolve the anchor from the latest message with this local agent execution mode. + pub anchor_agent_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `anchor=last_matching`, scope the anchor resolution to messages sent by this agent (`agi_...`). Combine with `anchor_agent_mode` to resolve the latest message from a specific agent in a given mode. + pub anchor_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, each message in the response is annotated with its threaded reply count. Defaults to `false`. Adds latency; omit when reply counts are not needed. + pub include_reply_counts: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponseDataMessagesItemAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponseDataMessagesItemAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponseDataMessagesItemAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponseDataMessagesItemAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponseDataMessagesItemActorsItemProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponseDataMessagesItemActorsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponseDataMessagesItemAttachmentsItemImageSource { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponseDataMessagesItemAttachmentsItemVariantsItemImageSource +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponseDataMessagesItemAttachmentsItemVariantsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of this variant's file (e.g., `"image/jpeg"`, `"video/mp4"`). `null` if the file is not loaded. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this variant was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file that backs this variant (`fil_...`). + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the uploaded file for this variant. `null` if the file is not loaded. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of this variant in pixels. `null` if not recorded. + pub height: Option, + /// Media variant ID (`mvr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types. + pub image_source: Option< + GetApiV1ThreadsThreadMessagesResponseDataMessagesItemAttachmentsItemVariantsItemImageSource, + >, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this variant was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed download URL for this variant, resolved at request time. `null` if the file is unavailable. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier for this variant's processing tier. Common values include `"original"` (the unmodified upload) and `"thumbnail"` (a resized preview). + pub variant_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of this variant in pixels. `null` if not recorded. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponseDataMessagesItemAttachmentsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the attached file, e.g. `"image/png"` or `"application/pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the attached file, e.g. `"report.pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height in pixels of the media item. Present on `media` type only. `null` otherwise. + pub height: Option, + /// Unique identifier for this attachment within the message. + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise. + pub image_height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise. + pub image_source: + Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise. + pub image_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise. + pub image_width: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The media category, e.g. `"video"` or `"audio"`. Present on `media` type only. `null` otherwise. + pub media_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the media item. Present on `media` type only. `null` otherwise. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types. + pub object: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types. + pub title: Option, + #[serde(rename = "type")] + /// The attachment type. One of `"file"`, `"scraped_link"`, `"artifact"`, `"task"`, `"media"`, `"action"`, or `"chart"`. Determines which additional fields are present. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise. + pub variants: Option< + Vec, + >, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise. + pub version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width in pixels of the media item. Present on `media` type only. `null` otherwise. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponseDataMessagesItemReactionsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Type-specific reaction data. For `"emoji_reaction"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `"👍"`). + pub payload: Option>, + #[serde(rename = "type")] + /// Reaction type identifier. Currently always `"emoji_reaction"` for emoji-based reactions. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Public ID of the user who added the reaction (`usr_...`). + pub user: Option, +} + +/// Contract-defined values for GetApiV1ThreadsThreadMessagesResponseDataMessagesItemAgentMode. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1ThreadsThreadMessagesResponseDataMessagesItemAgentMode { + /// The cli wire value. + #[serde(rename = "cli")] + Cli, + /// The embedded wire value. + #[serde(rename = "embedded")] + Embedded, +} + +/// Contract-defined values for GetApiV1ThreadsThreadMessagesResponseDataMessagesItemVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1ThreadsThreadMessagesResponseDataMessagesItemVisibility { + /// The default wire value. + #[serde(rename = "default")] + Default, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponseDataMessagesItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry. + pub actors: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path. + pub agent_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments. + pub attachments: + Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread. + pub branched_thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Text content of the message. `null` for messages that contain only attachments. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the message was posted (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this message has at least one reply. Only present when explicitly requested or computed by the server. + pub has_replies: Option, + /// Message ID (`msg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one. + pub idempotency_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages. + pub is_deleted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users. + pub legacy_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization that owns this message (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded. + pub reactions: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display hint for how the message should be rendered. One of `"reply"`, `"direct"`, or `"inline"`. `null` for user-authored messages, which are always rendered as standard replies. + pub rendering_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message. + pub replies: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response. + pub replies_after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response. + pub replies_before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of direct replies to this message. Only present when explicitly requested or computed by the server. + pub reply_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded. + pub reply_to: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages. + pub root_message_id: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread. + pub thread: Option, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees. + pub visibility: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponseData { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass as `after` to retrieve the page of messages newer than this result set. `null` when there are no later messages. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message ID used as the anchor for a windowed query. `null` for ordinary cursor pagination. + pub anchor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass as `before` to retrieve the page of messages older than this result set. `null` when there are no earlier messages. + pub before_cursor: Option, + /// Ordered array of message objects for this page of results. + pub messages: Vec, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMessagesResponse { + /// Pagination envelope containing the messages for this page along with cursors for adjacent pages. + pub data: GetApiV1ThreadsThreadMessagesResponseData, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1ThreadsThreadPictureInputPicture { + /// Base64-encoded binary content of the image file. + pub data: String, + /// Original filename of the image, e.g. `"avatar.png"`. Used for storage and display. + pub filename: String, + /// MIME type of the image, e.g. `"image/jpeg"` or `"image/png"`. + pub mime_type: String, +} + +/// Uploads a new profile picture for the specified thread and returns the updated +/// thread object. The image must be supplied as a base64-encoded string with its +/// MIME type. +/// +/// The authenticated user must own the thread or be a team owner of the workspace +/// the thread belongs to. Supplying invalid base64 data returns 422. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1ThreadsThreadPictureInput { + /// Profile picture payload. Must include the base64-encoded image data and its MIME type. + pub picture: PutApiV1ThreadsThreadPictureInputPicture, +} + +/// Query parameters for get_api_v1_threads__thread_read_status. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadReadStatusParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID (`usr_...`) whose read status to retrieve. Required for S2S requests; ignored for user-authenticated requests, which always return the status for the authenticated user. + pub user: Option, +} + +/// Contract-defined values for GetApiV1ThreadsThreadSearchParamsMode. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1ThreadsThreadSearchParamsMode { + /// The text wire value. + #[serde(rename = "text")] + Text, + /// The embedding wire value. + #[serde(rename = "embedding")] + Embedding, + /// The hybrid wire value. + #[serde(rename = "hybrid")] + Hybrid, +} + +/// Query parameters for get_api_v1_threads__thread_search. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadSearchParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// App ID (`app_...`). Required by the protected developer mount and omitted from the public mount. + pub app: Option, + /// Text or semantic search query. Must contain 3 to 200 characters after trimming. + pub q: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of results. Defaults to 20 and is capped at 20. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Search algorithm: `text` for substring matching, `embedding` for cosine similarity, or `hybrid` for RRF over both rankings. + pub mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Text mode only. Opaque cursor returned by a previous page; fetches older matches. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Text mode only. Opaque cursor returned by a previous page; fetches newer matches. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadSearchResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent sender ID (`agi_...`), or `null` when a human sent the message. + pub agent: Option, + /// A bounded snippet around the first matching occurrence (at most 240 characters). + pub content: String, + /// When the message was posted. + pub created_at: chrono::DateTime, + /// Message ID (`msg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Cosine similarity to the query when the result participated in embedding search, or `null` in text mode and for text-only hybrid matches. + pub similarity_score: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human sender ID (`usr_...`), or `null` when an agent sent the message. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadSearchResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Text-mode cursor for the next page of newer matches, or `null` for ranked modes and empty pages. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Text-mode cursor for the next page of older matches, or `null` for ranked modes and empty pages. + pub before_cursor: Option, + /// Matching messages ordered newest first in text mode and by relevance in embedding or hybrid mode. + pub data: Vec, + /// `true` when at least one additional visible match exists. + pub has_more: bool, +} + +/// Query parameters for get_api_v1_threads__thread_trajectories. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadTrajectoriesParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor from a previous response's `before_cursor` field. Returns the page of results preceding that cursor position. + pub before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor from a previous response's `after_cursor` field. Returns the page of results following that cursor position. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of trajectories to return per page. Defaults to 20; maximum is 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message ID (`msg_...`). When provided, limits results to trajectories associated with this specific message. + pub message: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadTrajectoriesResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent-authored reply message (`msg_...`). `null` if the trajectory has not yet produced a response message. + pub agent_message: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this trajectory link was created (ISO 8601). + pub created_at: Option>, + /// Thread message trajectory ID (`tmt_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this trajectory belongs to (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment in which this trajectory was produced (`dsb_...`). `null` in production contexts. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread containing the linked messages (`thr_...`). + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the AI trajectory record that captures the full model interaction for this exchange (`trj_...`). + pub trajectory: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this trajectory link was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user-authored message that triggered the agent response (`msg_...`). `null` if the agent turn was not preceded by a user message. + pub user_message: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadTrajectoriesResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass as `after_cursor` to retrieve the next page. `null` when no further pages exist. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor to pass as `before_cursor` to retrieve the previous page. `null` when this is the first page. + pub before_cursor: Option, + /// Array of thread message trajectory objects for the current page. Empty when no trajectories match the query. + pub data: Vec, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMembersResponseDataItemAgent { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent email address. `null` if not configured. + pub email: Option, + /// Agent ID (`agi_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable agent name. `null` if not set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization that owns this agent (`org_...`). `null` if not org-scoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team that owns this agent (`tem_...`). `null` if not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User that owns this agent (`usr_...`). `null` if not user-scoped. + pub user: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMembersResponseDataItemUser { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User's email address. `null` if not set. + pub email: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Backward-compatible alias of `name`. `null` if not set. + pub full_name: Option, + /// User ID (`usr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full display name of the user. `null` if not set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization this user belongs to (`org_...`). `null` if the user is not org-scoped. + pub org: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMembersResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Roster-safe agent identity. Populated for agent members; `null` for users. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this member joined the thread (ISO 8601). + pub joined_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Backward-compatible alias of `type`. + pub member_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Role of this member, commonly `"owner"` or `"member"`. + pub membership_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Backward-compatible alias of `membership_type`. + pub role: Option, + #[serde(rename = "type")] + /// Kind of participant. One of `"user"` or `"agent"`. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Roster-safe user identity. Populated for user members; `null` for agents. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadMembersResponse { + /// Array of thread member objects representing all current members of the thread. + pub data: Vec, +} + +/// Adds a user or agent to the explicit roster of a private or restricted +/// thread. Team-visible threads use the owning team's implicit roster and reject +/// explicit additions. On restricted threads, a team member may add themself; +/// adding anyone else requires permission to modify the thread. +/// +/// Supply either `user` or `agent` depending on the value of `type`. Targets +/// must be visible to the caller and, for an ordinary team-owned thread, must +/// belong to the owning team. On success the membership record is returned with +/// HTTP 201; repeated agent additions are idempotent. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ThreadsThreadMembersInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Agent ID of the principal to add. Required when `type` is `"agent"`. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Role granted to the new member. One of `"owner"` or `"member"`. Defaults to `"member"`. + pub membership_type: Option, + #[serde(rename = "type")] + /// Kind of principal being added. Must be `"user"` or `"agent"`. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User ID of the principal to add. Required when `type` is `"user"`. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1ThreadsThreadSettingsResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether the AI agent is active for this thread. Defaults to `true` when no settings have been explicitly set. + pub agent_enabled: Option, +} + +/// Updates the settings for the specified thread. Only fields included in +/// the `settings` map are modified; omitted fields retain their current values. +/// +/// The authenticated user must own the thread or be a member of its workspace. +/// Returns the full settings object reflecting the state after the update. +/// Validation errors are returned as `422 Unprocessable Entity`. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1ThreadsThreadSettingsInput { + /// Map of settings fields to update. Include only the keys you want to change. + pub settings: std::collections::BTreeMap, +} + +/// Adds one or more status tags to the thread and returns the updated thread. +/// +/// Any participant of the thread — a human member or an agent member — may edit +/// tags; this is broader than the owner/admin permission required to update other +/// thread fields. Adding a tag the thread already has is a no-op. Tags are +/// normalized (trimmed and lowercased) and may contain only lowercase letters, +/// numbers, hyphens, and underscores. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1ThreadsThreadTagsInput { + /// Tags to add to the thread. + pub tags: Vec, +} + +/// Replaces the thread's entire set of status tags with the provided list and +/// returns the updated thread. Passing an empty array clears all tags. +/// +/// Any participant of the thread — a human member or an agent member — may edit +/// tags. Tags are normalized (trimmed and lowercased) and may contain only +/// lowercase letters, numbers, hyphens, and underscores. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1ThreadsThreadTagsInput { + /// The complete set of tags for the thread. An empty array clears all tags. + pub tags: Vec, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserArtifactsResponseDataItemImageSource { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserArtifactsResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that produced this artifact (`agt_...`). `null` if not agent-produced. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the current version's file, e.g. `"text/csv"` or `"image/png"`. `null` if no file is attached. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the artifact was first created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the current (latest published) artifact version (`artv_...`). `null` if no version has been published. + pub current_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional longer description of the artifact's contents or purpose. `null` if not set. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Storage file ID for the current version (`fil_...`). `null` if no file is attached. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the current version's file, e.g. `"output.csv"`. `null` if no file is attached. + pub file_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short-lived signed URL for downloading the current version's file. `null` if no file is attached. + pub file_url: Option, + /// Artifact ID (`art_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Image source metadata for rendering the current version's file inline. Present only when `content_type` starts with `"image/"`. `null` otherwise. + pub image_source: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable name for the artifact, e.g. `"Q2 Report"`. `null` if not set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this artifact belongs to (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the sandbox environment associated with this artifact. `null` if not sandbox-scoped. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this artifact (`tea_...`). `null` if not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread in which this artifact was created (`thr_...`). `null` if not thread-scoped. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the artifact record was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this artifact (`usr_...`). `null` if not user-scoped. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current version number of the artifact. Increments each time a new version is published. + pub version: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserArtifactsResponse { + /// Array of artifact objects belonging to the user. + pub data: Vec, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1UsersUserInvitesInputInvite { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to attach to the invite. Returned as-is on the resulting invite object. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the persona to associate with this invite (`per_...`). `null` if the invite is not bound to a persona. + pub persona_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread to associate with this invite (`thr_...`). `null` if the invite is not bound to a thread. + pub thread_id: Option, +} + +/// Creates a new invite for the authenticated user. The invite can optionally be +/// scoped to a specific thread, a persona, or carry arbitrary metadata. The +/// caller receives the new invite object at HTTP 201. +/// +/// The invite key is always generated server-side (192-bit URL-safe random +/// string) and cannot be supplied by the caller. +/// +/// The path `:user` must match the authenticated user. If a `thread_id` is +/// provided, the authenticated user must have permission to invite others to that +/// thread; team threads are not supported and return an error. Supplying a +/// `thread_id` that does not exist or that belongs to a different user returns +/// an error. If a key collision occurs during creation the call returns a 409 +/// conflict — simply retry to generate a new key. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1UsersUserInvitesInput { + /// Parameters for the new invite. See the UserInviteCreateParams schema for field details. + pub invite: PostApiV1UsersUserInvitesInputInvite, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserOrgsResponseDataItemVendorLogo { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserOrgsResponseDataItemVendor { + /// Organization ID of the vendor (`org_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Logo of the vendor organization. The `url` is a stable, non-expiring capability URL served by the platform (the same mechanism as catalog `org_logo` fields), safe to hold in caches; `refresh_url` is `null`. `null` when the vendor has no logo. + pub logo: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the vendor organization. `null` if the vendor has not set a name. + pub name: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserOrgsResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this organization was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short human-readable description of the organization. `null` if not set. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Primary domain associated with the organization, e.g. `"acme.com"`. `null` if not configured. + pub domain: Option, + /// Organization ID (`org_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Industry category the organization belongs to, e.g. `"fintech"` or `"healthcare"`. `null` if not set. + pub industry: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the organization. `null` if the org has not set a name. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lookup key (`sol-...`) of the Solution that drove this org's customer onboarding, stamped when the org was first linked into a vendor's network via an explore-install. `null` for vendor-track orgs and invite-driven customers. The onboarding UI reads the referenced Solution's `metadata.onboarding` block to tailor the customer checklist. + pub onboarding_solution_lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The new-user experience track this org first completed. `"vendor"` for orgs that onboarded as service providers; `"customer"` for orgs that onboarded as buyers. `null` if onboarding was not tracked. + pub onboarding_track: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Catalog product IDs this organization's plan includes, e.g. `["agent-rooms"]`, `["agent-solutions"]`, `["agent-customer-management"]`. Empty when the org has no plan. Clients use this to show which products the org actually has rather than inferring from feature flags. Derived from the org's plan, so it reflects what is currently paid for. + pub owned_products: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment scoped to this organization (`snd_...`). `null` for organizations in production mode. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL-safe identifier for the organization, used in vanity URLs and slug-based lookups. + pub slug: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Current lifecycle status of the organization, e.g. `"active"` or `"suspended"`. `null` if the status has not been set. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this organization was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Branding of the solution vendor whose network this organization belongs to — the vendor of the oldest active vendor relationship. Only present for organizations on the `"customer"` onboarding track; `null` for vendor-track organizations (including vendors that later joined another vendor's network) and for customers with no active vendor link. Clients use it to co-brand the workspace ("ArchAgents by Acme"). + pub vendor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Public website URL for the organization. `null` if not set. + pub website: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserOrgsResponse { + /// Array of organization objects the user belongs to. Contains at most one item. + pub data: Vec, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1UsersUserProfileInputProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Base64-encoded binary content of the image file. + pub data: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the image, used for storage metadata. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. + pub mime_type: Option, +} + +/// Updates one or more profile fields for the authenticated user. All +/// fields are optional; omit any you do not want to change. +/// +/// When `profile_picture` is supplied, the image is uploaded and replaces +/// the existing picture. The previous picture is deleted after the new one +/// is stored. Image upload failures return 422 without modifying other +/// profile fields. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PutApiV1UsersUserProfileInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short display alias shown in place of the full name in compact UI contexts. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Updated display name for the user. + pub full_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata to associate with the user. Existing keys are merged; pass `null` for a key to remove it. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// New profile picture to upload as a base64-encoded image. Replaces any existing picture. + pub profile_picture: Option, +} + +/// Query parameters for get_api_v1_users__user_tasks. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`tem_...`). Only tasks belonging to this team are returned. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional organization (`org_...`) for developer and server-to-server calls. When omitted, the org is taken from the owner principal (team, user, or agent). When set, it must match that principal's org; pass null for an owner outside an organization. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter tasks by status. One of `"open"`, `"in_progress"`, or `"done"`. Omit to return tasks in all statuses. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter tasks assigned to a specific user. Provide the user's public ID (`usr_...`). + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter tasks assigned to a specific agent. Provide the agent's public ID (`agi_...`). + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter tasks by priority, from 0 (highest) to 4 (lowest). + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only tasks carrying this tag (matched against the canonical lowercase form). + pub tag: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only subtasks of the given task (`tsk_...`), or pass `none` to return only top-level tasks. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to tasks whose name or description contains this string. + pub search: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sort key. One of `"created"` (default — most recently created first), `"due_date"` (soonest due first; tasks without a due date always sort last), or `"priority"` (most urgent first). Ties break by most recently created. + pub sort: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sort direction, `"asc"` or `"desc"`. Defaults to `"desc"` for `created` and `"asc"` for `due_date` and `priority`. + pub order: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only tasks with a due date strictly before this ISO 8601 datetime (`2026-08-01T00:00:00Z`) or date (`2026-08-01`, meaning midnight UTC). Tasks without a due date are excluded. + pub due_before: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only tasks with a due date strictly after this ISO 8601 datetime or date. Tasks without a due date are excluded. + pub due_after: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, return only overdue tasks: a due date before the current UTC day and a status other than `"done"`. A task due today is not overdue. + pub overdue: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When true, return only open tasks with no unfinished blockers and no active session lease. This is a projection snapshot; claim a lease before starting work. + pub ready: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of tasks to return. Capped at 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the previous page. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksResponseDataItemCreatedByActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksResponseDataItemCreatedByActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksResponseDataItemCurrentLease { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the coding session. + pub harness: String, + /// Display name supplied by the coding session that holds the lease. + pub session_name: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksResponseDataItemOwnerActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksResponseDataItemOwnerActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind. + pub blocked_by_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open. + pub closed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of comments posted on this task. + pub comments_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted). + pub created_by_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted. + pub created_by_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted. + pub created_by_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included. + pub current_lease: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Long-form description or notes for the task. `null` if no description has been provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). `null` if no due date is set. + pub due_date: Option>, + /// Task ID (`tsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read. + pub is_blocked: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set. + pub metadata: Option>, + /// Human-readable title of the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted). + pub owner_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment. + pub sandbox: Option, + /// Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks. + pub subtasks_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + /// Array of task objects matching the requested filters. + pub data: Vec, + /// API field. + pub has_more: bool, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1UsersUserTasksInputTask { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional long-form description or notes for the task. Supports plain text. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). Omit to create the task without a due date. + pub due_date: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of named URLs or references associated with the task (e.g. external ticket links). + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map for storing application-specific data alongside the task. Omit to create the task with no metadata. + pub metadata: Option>, + /// Human-readable title for the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent to assign as owner (`agi_...`). Mutually exclusive with `owner_user`; omit to leave the task unassigned. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user to assign as owner (`usr_...`). Mutually exclusive with `owner_agent`; omit to leave the task unassigned. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Create this task as a subtask of an existing top-level task (`tsk_...`). Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when omitted. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Initial status for the task. One of `"open"`, `"in_progress"`, or `"done"`. Defaults to `"open"` when omitted. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering (max 20, each up to 40 characters). Stored canonically: lowercase, trimmed, de-duplicated. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Bind the task to a thread (`thr_...`) owned by the same team or user as the task. A bound task appears in that thread's task scope, exactly like a task filed from inside the conversation. Omit for a task not tied to a conversation. + pub thread: Option, +} + +/// Creates a new task owned by the specified user or team and returns the full +/// task object. User-authenticated calls are attributed to the authenticated +/// user or agent. App-scoped developer and server-to-server callers must provide +/// the task's explicit `org` scope and an explicit `user` or `agent` actor for +/// team tasks; a user-owned task reuses the user in the route unless an explicit +/// agent is supplied. Every referenced principal is validated against the app, +/// owner, and team membership before creation. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1UsersUserTasksInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit acting agent (`agi_...`) for a developer or server-to-server call. Mutually exclusive with an acting `user`; the agent must belong to the task owner. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit organization (`org_...`) for developer and server-to-server calls. Pass null when the owner is not organization-scoped. The value must match the selected user or team. + pub org: Option, + /// Attributes for the task to create. `name` is required; all other fields are optional. + pub task: PostApiV1UsersUserTasksInputTask, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`tem_...`). The task will be owned by this team. + pub team: Option, +} + +/// Query parameters for get_api_v1_users__user_tasks_blocker_cycles. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksBlockerCyclesParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`tem_...`) owning the tasks. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional organization context for privileged callers. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum cycle components to return. Defaults to 50; maximum is 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the preceding page. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksBlockerCyclesResponseDataItemTasksItemCreatedByActorProfilePicture +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksBlockerCyclesResponseDataItemTasksItemCreatedByActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option< + GetApiV1UsersUserTasksBlockerCyclesResponseDataItemTasksItemCreatedByActorProfilePicture, + >, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksBlockerCyclesResponseDataItemTasksItemCurrentLease { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the coding session. + pub harness: String, + /// Display name supplied by the coding session that holds the lease. + pub session_name: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksBlockerCyclesResponseDataItemTasksItemOwnerActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksBlockerCyclesResponseDataItemTasksItemOwnerActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: Option< + GetApiV1UsersUserTasksBlockerCyclesResponseDataItemTasksItemOwnerActorProfilePicture, + >, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksBlockerCyclesResponseDataItemTasksItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind. + pub blocked_by_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open. + pub closed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of comments posted on this task. + pub comments_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted). + pub created_by_actor: + Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted. + pub created_by_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted. + pub created_by_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included. + pub current_lease: + Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Long-form description or notes for the task. `null` if no description has been provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). `null` if no due date is set. + pub due_date: Option>, + /// Task ID (`tsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read. + pub is_blocked: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set. + pub metadata: Option>, + /// Human-readable title of the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted). + pub owner_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment. + pub sandbox: Option, + /// Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks. + pub subtasks_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team. + pub user: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksBlockerCyclesResponseDataItem { + /// Every unfinished task in this cyclic blocker component. + pub tasks: Vec, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksBlockerCyclesResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + /// API field. + pub data: Vec, + /// API field. + pub has_more: bool, +} + +/// Query parameters for get_api_v1_users__user_tasks_ready. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksReadyParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`tem_...`) owning the tasks. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional organization context for privileged callers. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Include blocked and actively leased open tasks with exclusion reasons. + pub explain: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Only include tasks assigned to the authenticated user. + pub assigned_to_me: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of readiness entries to return. Capped at 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the previous page. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksReadyResponseDataItemTaskCreatedByActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksReadyResponseDataItemTaskCreatedByActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksReadyResponseDataItemTaskCurrentLease { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the coding session. + pub harness: String, + /// Display name supplied by the coding session that holds the lease. + pub session_name: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksReadyResponseDataItemTaskOwnerActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksReadyResponseDataItemTaskOwnerActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksReadyResponseDataItemTask { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind. + pub blocked_by_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open. + pub closed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of comments posted on this task. + pub comments_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted). + pub created_by_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted. + pub created_by_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted. + pub created_by_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included. + pub current_lease: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Long-form description or notes for the task. `null` if no description has been provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). `null` if no due date is set. + pub due_date: Option>, + /// Task ID (`tsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read. + pub is_blocked: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set. + pub metadata: Option>, + /// Human-readable title of the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted). + pub owner_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment. + pub sandbox: Option, + /// Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks. + pub subtasks_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team. + pub user: Option, +} + +/// Contract-defined values for GetApiV1UsersUserTasksReadyResponseDataItemReadiness. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1UsersUserTasksReadyResponseDataItemReadiness { + /// The ready wire value. + #[serde(rename = "ready")] + Ready, + /// The blocked wire value. + #[serde(rename = "blocked")] + Blocked, + /// The leased wire value. + #[serde(rename = "leased")] + Leased, +} + +/// Contract-defined values for GetApiV1UsersUserTasksReadyResponseDataItemReason. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1UsersUserTasksReadyResponseDataItemReason { + /// The open_blockers wire value. + #[serde(rename = "open_blockers")] + OpenBlockers, + /// The active_lease wire value. + #[serde(rename = "active_lease")] + ActiveLease, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksReadyResponseDataItem { + /// One of `ready`, `blocked`, or `leased`. + pub readiness: GetApiV1UsersUserTasksReadyResponseDataItemReadiness, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable exclusion reason: `open_blockers` or `active_lease`; omitted when ready. + pub reason: Option, + /// The task evaluated for readiness. + pub task: GetApiV1UsersUserTasksReadyResponseDataItemTask, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksReadyResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + /// Always false because projections can lag writes and a later claim can race this read. + pub authoritative: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + /// API field. + pub data: Vec, + /// API field. + pub has_more: bool, +} + +/// Query parameters for get_api_v1_users__user_tasks_search. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksSearchParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Team ID (`tem_...`). Only tasks belonging to this team are searched. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional organization (`org_...`) for developer and server-to-server calls. When omitted, the org is taken from the owner principal (team, user, or agent). When set, it must match that principal's org; pass null for an owner outside an organization. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full-text search query matched against task names and descriptions. Takes precedence over `query` when both are provided. + pub q: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Alias for `q`. Use `q` when possible; this parameter exists for compatibility. + pub query: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results by status. One of `"open"`, `"in_progress"`, or `"done"`. Omit to include all statuses. + pub status: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to tasks assigned to the user with this public ID (`usr_...`). + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Restrict results to tasks assigned to the agent with this public ID (`agi_...`). + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Filter results by priority, from 0 (highest) to 4 (lowest). + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only tasks carrying this tag (matched against the canonical lowercase form). + pub tag: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Return only subtasks of the given task (`tsk_...`), or pass `none` to return only top-level tasks. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of tasks to return. Capped at 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor returned by the previous page. + pub after_cursor: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksSearchResponseDataItemCreatedByActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksSearchResponseDataItemCreatedByActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksSearchResponseDataItemCurrentLease { + /// Server-calculated lease expiry in ISO 8601 format. + pub expires_at: chrono::DateTime, + /// Bounded harness identifier for the coding session. + pub harness: String, + /// Display name supplied by the coding session that holds the lease. + pub session_name: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksSearchResponseDataItemOwnerActorProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksSearchResponseDataItemOwnerActor { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksSearchResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind. + pub blocked_by_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open. + pub closed_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of comments posted on this task. + pub comments_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted). + pub created_by_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted. + pub created_by_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted. + pub created_by_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included. + pub current_lease: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Long-form description or notes for the task. `null` if no description has been provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Date and time by which the task should be completed (ISO 8601). `null` if no due date is set. + pub due_date: Option>, + /// Task ID (`tsk_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` while at least one blocking task is not yet done. Informational only — a blocked task can still change status — and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read. + pub is_blocked: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set. + pub links: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set. + pub metadata: Option>, + /// Human-readable title of the task. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted). + pub owner_actor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted. + pub owner_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted. + pub owner_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level. + pub parent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set. + pub priority: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment. + pub sandbox: Option, + /// Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`. + pub status: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks. + pub subtasks_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this task is bound to (`thr_...`) — the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread. + pub thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the task was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team. + pub user: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTasksSearchResponse { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// API field. + pub before_cursor: Option, + /// Array of task objects matching the query and filters. + pub data: Vec, + /// API field. + pub has_more: bool, + /// API field. + pub query: String, +} + +/// Query parameters for get_api_v1_users__user_threads. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of agent user IDs (`usr_...`). When provided, only threads where at least one of the listed agents is also a member are returned. Omit or pass an empty array to return all threads regardless of agent membership. + pub agent: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of metadata filter objects. Each filter matches threads whose `metadata` map contains the specified key/value pair. All filters must match (logical AND). Omit to return threads regardless of metadata. + pub filter: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParentMessageAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParentMessageAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParentMessageAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParentMessageAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParentMessageActorsItemProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParentMessageActorsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifier. Format is `"user-"` for human users or `"agent-"` for agents. + pub id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the actor shown in the UI. `null` if no name is set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Profile picture for the actor. `null` if the actor has no profile picture. + pub profile_picture: + Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParentMessageAttachmentsItemImageSource { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParentMessageAttachmentsItemVariantsItemImageSource +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParentMessageAttachmentsItemVariantsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of this variant's file (e.g., `"image/jpeg"`, `"video/mp4"`). `null` if the file is not loaded. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this variant was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file that backs this variant (`fil_...`). + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the uploaded file for this variant. `null` if the file is not loaded. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of this variant in pixels. `null` if not recorded. + pub height: Option, + /// Media variant ID (`mvr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types. + pub image_source: Option< + GetApiV1UsersUserThreadsResponseDataItemParentMessageAttachmentsItemVariantsItemImageSource, + >, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this variant was last updated (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed download URL for this variant, resolved at request time. `null` if the file is unavailable. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier for this variant's processing tier. Common values include `"original"` (the unmodified upload) and `"thumbnail"` (a resized preview). + pub variant_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of this variant in pixels. `null` if not recorded. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParentMessageAttachmentsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the attached file, e.g. `"image/png"` or `"application/pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise. + pub content_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the attached file, e.g. `"report.pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height in pixels of the media item. Present on `media` type only. `null` otherwise. + pub height: Option, + /// Unique identifier for this attachment within the message. + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise. + pub image_height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise. + pub image_source: + Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise. + pub image_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise. + pub image_width: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The media category, e.g. `"video"` or `"audio"`. Present on `media` type only. `null` otherwise. + pub media_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the media item. Present on `media` type only. `null` otherwise. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. `null` on other types. + pub object: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types. + pub title: Option, + #[serde(rename = "type")] + /// The attachment type. One of `"file"`, `"scraped_link"`, `"artifact"`, `"task"`, `"media"`, `"action"`, or `"chart"`. Determines which additional fields are present. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only. `null` otherwise. + pub variants: Option< + Vec, + >, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise. + pub version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width in pixels of the media item. Present on `media` type only. `null` otherwise. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParentMessageReactionsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Type-specific reaction data. For `"emoji_reaction"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `"👍"`). + pub payload: Option>, + #[serde(rename = "type")] + /// Reaction type identifier. Currently always `"emoji_reaction"` for emoji-based reactions. + pub type_: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Public ID of the user who added the reaction (`usr_...`). + pub user: Option, +} + +/// Contract-defined values for GetApiV1UsersUserThreadsResponseDataItemParentMessageAgentMode. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1UsersUserThreadsResponseDataItemParentMessageAgentMode { + /// The cli wire value. + #[serde(rename = "cli")] + Cli, + /// The embedded wire value. + #[serde(rename = "embedded")] + Embedded, +} + +/// Contract-defined values for GetApiV1UsersUserThreadsResponseDataItemParentMessageVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1UsersUserThreadsResponseDataItemParentMessageVisibility { + /// The default wire value. + #[serde(rename = "default")] + Default, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParentMessage { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry. + pub actors: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users. + pub agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path. + pub agent_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments. + pub attachments: + Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread. + pub branched_thread: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Text content of the message. `null` for messages that contain only attachments. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the message was posted (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this message has at least one reply. Only present when explicitly requested or computed by the server. + pub has_replies: Option, + /// Message ID (`msg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one. + pub idempotency_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages. + pub is_deleted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users. + pub legacy_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization that owns this message (`org_...`). + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded. + pub reactions: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display hint for how the message should be rendered. One of `"reply"`, `"direct"`, or `"inline"`. `null` for user-authored messages, which are always rendered as standard replies. + pub rendering_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message. + pub replies: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response. + pub replies_after_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response. + pub replies_before_cursor: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Total number of direct replies to this message. Only present when explicitly requested or computed by the server. + pub reply_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded. + pub reply_to: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages. + pub root_message_id: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the thread this message belongs to (`thr_...`). `null` for messages not yet associated with a thread. + pub thread: Option, + #[serde(rename = "type")] + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset. + pub type_: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents. + pub user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees. + pub visibility: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipantsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short handle or alias for the user. `null` if not set. + pub alias: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the app this user (and their access token) is scoped to (`dap_...`). `null` if the user is not scoped to an app. + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the user's app. `null` when the app association was not preloaded by the caller. + pub app_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address of the user. + pub email: Option, + /// User ID (`usr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// `true` if this account is an internal system user rather than a human. System users are created automatically by the platform. + pub is_system_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the user. Defaults to an empty object. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Full display name of the user. `null` if the user has not set a name. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this user belongs to (`org_...`). `null` if the user is not a member of any organization. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Role of the user within their organization. One of `"admin"`, `"member"`, or `"viewer"`. `null` when the user is not a member of any organization. + pub org_role: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable workspace slug for the user's organization. `null` when the user is not in an org, or when the org association was not preloaded by the caller. + pub org_slug: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment this user is scoped to (`sbx_...`). `null` for production users. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the user's sandbox environment. `null` for production users, or when the sandbox association was not preloaded by the caller. + pub sandbox_name: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemAclAddItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemAclGrantsItem { + /// Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry. + pub actions: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemAclRemoveItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`. + pub principal: Option, + /// The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`. + pub principal_type: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemAcl { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`. + pub add: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`. + pub grants: + Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`. + pub remove: + Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionOrgLogo +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsInvokeContractParticipantsItem +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Workflow-authored explanation of the slot's role. `null` when the workflow declares none. + pub description: Option, + /// The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking. + pub name: String, + /// Whether the workflow requires this slot to be filled for the run to complete its embedded stages. + pub required: bool, + #[serde(rename = "type")] + /// The kind of principal the slot accepts. Currently always `"agent_user"` — the value supplied at invoke is an agent ID (`agi_...`). + pub type_: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsInvokeContractPrefills +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected. + pub payload: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsInvokeContract { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured. + pub input_schema: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs. + pub participants: Option>, + /// Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected. + pub prefills: GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsInvokeContractPrefills, +} + +/// Contract-defined values for GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsType +{ + /// The automation wire value. + #[serde(rename = "automation")] + Automation, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetails { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Automation execution type (`invoked`, `scheduled`, or `trigger`). + pub automation_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning. + pub invoke_contract: Option, + #[serde(rename = "type")] + /// Template-details discriminator. Always `automation` for this variant. + pub type_: GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItemDetailsType, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolutionTemplatesItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details. + pub details: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`. + pub display_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template config ID (`cfg_...`). `null` for inline-only templates. + pub id: Option, + /// Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lookup key stamped on the template config at import time. `null` when no lookup key was assigned. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable virtual path assigned to the template config. `null` when no virtual path was set. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionCurrentSolution { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none. + pub category_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was first imported (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none. + pub events: Option>, + /// Solution config ID (`cfg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only. + pub image_url: Option, + /// Resource type. Always `"Solution"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise. + pub latest_solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise. + pub latest_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing display name declared in the Solution body. `null` when the Solution body does not set one. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo. + pub org_logo: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve. + pub org_slug: Option, + /// Owner scopes this Solution appears under. Members: `"system"` (app-level system scope) and/or `"org"` (viewer's org scope). + pub owners: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only. + pub screenshot_urls: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it. + pub solution_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Semver string declared in the Solution body (e.g. `"1.2.0"`). `null` when the body does not declare a version. + pub solution_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Freeform tag keys declared in the Solution body. An empty array when the body declares none. + pub tag_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Wrapped template kind — `"AgentTemplate"`, `"AutomationTemplate"`, `"AgentRoutineTemplate"`, `"AgentToolTemplate"`, `"AgentComputerTemplate"`, or `"SolutionTemplateRef"` for ref-mode bundles. + pub template_kind: Option, + /// Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references. + pub templates: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was last modified (ISO 8601). + pub updated_at: Option>, + /// `true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows. + pub upgrade_available: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionOrgLogo +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file. + pub file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Height of the image in pixels. `null` if not known. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity. + pub media: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known. + pub mime_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing. + pub refresh_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires. + pub url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Width of the image in pixels. `null` if not known. + pub width: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsInvokeContractParticipantsItem +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Workflow-authored explanation of the slot's role. `null` when the workflow declares none. + pub description: Option, + /// The slot's name, as referenced by the workflow. Supply the chosen agent under the top-level `participants[name]` field when invoking. + pub name: String, + /// Whether the workflow requires this slot to be filled for the run to complete its embedded stages. + pub required: bool, + #[serde(rename = "type")] + /// The kind of principal the slot accepts. Currently always `"agent_user"` — the value supplied at invoke is an agent ID (`agi_...`). + pub type_: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsInvokeContractPrefills +{ + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Participant slot-to-agent mappings applied by the platform. Caller values at these slots must match exactly. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Partial invocation payload applied by the platform. A caller may omit these values, but supplying a different value at any locked path is rejected. + pub payload: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsInvokeContract { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// JSON Schema validated against the whole invoke payload, from the automation's `input_schema_config`. `null` when none is configured. + pub input_schema: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Named participant slots declared by the workflow, sorted by name. `null` when the workflow declares none. Values supplied under the top-level `participants` field are agent IDs. + pub participants: Option>, + /// Owner-controlled payload and participant values the platform applies to every invocation. Supplying a conflicting value is rejected. + pub prefills: GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsInvokeContractPrefills, +} + +/// Contract-defined values for GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsType +{ + /// The automation wire value. + #[serde(rename = "automation")] + Automation, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetails { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Automation execution type (`invoked`, `scheduled`, or `trigger`). + pub automation_type: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Schema-driven payload and participant inputs for an invoked automation. Used by installation clients to collect locked prefills before provisioning. + pub invoke_contract: Option, + #[serde(rename = "type")] + /// Template-details discriminator. Always `automation` for this variant. + pub type_: GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItemDetailsType, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short prose blurb from the template body's `description:` field. `null` when the body doesn't set one. Used as the card subhead in the Library carousel. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template-kind-specific details selected by the `type` discriminator. `null` when this template kind has no additional details. + pub details: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing label from the template body's `display_name:` field. `null` when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`. + pub display_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template config ID (`cfg_...`). `null` for inline-only templates. + pub id: Option, + /// Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lookup key stamped on the template config at import time. `null` when no lookup key was assigned. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. `null` when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable virtual path assigned to the template config. `null` when no virtual path was set. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolution { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Category tag keys declared in the Solution body, used to group Solutions in the catalog. An empty array when the body declares none. + pub category_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was first imported (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Short tagline or summary declared in the Solution body, used as the card subhead in catalog UIs. `null` when the Solution body does not set one. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Custom analytics events declared in the Solution body's `events:` manifest — a map of event key (snake_case) to its definition (`label`, optional `description`, optional typed `fields`). Dashboards use the `label` as the event's display name. Present as an empty object when the body declares none. + pub events: Option>, + /// Solution config ID (`cfg_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URL of the Solution's cover image — the bundled asset the body's `image:` field names. A stable, non-expiring capability URL (like `org_logo.url`), safe to hold in caches and OpenGraph tags; it 404s if the Solution stops declaring a cover. `null` when the Solution has no cover image, and always `null` for org-scoped rows — the permanent URL is minted for system-scope (catalog) Solutions only. + pub image_url: Option, + /// Resource type. Always `"Solution"`. + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the system-scope Solution config ID (`cfg_...`) that should be used as the upgrade source. `null` otherwise. + pub latest_solution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `upgrade_available` is `true`, the higher system-scope `solution_version` available to upgrade to. `null` otherwise. + pub latest_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The lookup key stored on the Solution config, if one was assigned during import. `null` when no lookup key was set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata declared in the Solution body (e.g. category or display hints). Present as an empty object when the body declares none. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-facing display name declared in the Solution body. `null` when the Solution body does not set one. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Organization ID (`org_...`) that owns this Solution config, when the Solution is scoped to a specific org. `null` for system-scope (app-level) Solutions. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Canonical image-source object for the resolved `org`'s logo, used as the principal category section glyph. The `url` is a stable, non-expiring capability URL (`refresh_url` is `null` — there is nothing to refresh). `null` when `org_slug` is `null` or the org has no logo. + pub org_logo: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the resolved `org`. Pairs with `org_slug` as the principal catalog category's label. `null` when `org_slug` is `null`. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Resolved slug of the Solution body's `org` (the publishing organization), when set and it resolves to a real org visible to the viewer. When present this is the Solution's principal catalog category key — clients group the Solution under this org ahead of `category_keys`. `null` when the body has no `org` or it doesn't resolve. + pub org_slug: Option, + /// Owner scopes this Solution appears under. Members: `"system"` (app-level system scope) and/or `"org"` (viewer's org scope). + pub owners: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Relative path to the public README endpoint with a signed token already embedded. `null` when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`. + pub readme_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Absolute URLs of the Solution's gallery screenshots — the bundled assets the body's `screenshots:` field names, in declared order. Each is a stable, non-expiring capability URL with the same cacheability contract as `image_url` (one shared token, a `v` cache key, and a `file` param selecting the screenshot); a URL 404s if the Solution stops declaring its screenshot. An empty array when the Solution declares none, and always empty for org-scoped rows — the permanent URLs are minted for system-scope (catalog) Solutions only. + pub screenshot_urls: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable UUID declared in the Solution body, used to identify the same logical Solution across multiple installed copies and owner scopes. `null` when the body omits it. + pub solution_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Semver string declared in the Solution body (e.g. `"1.2.0"`). `null` when the body does not declare a version. + pub solution_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Freeform tag keys declared in the Solution body. An empty array when the body declares none. + pub tag_keys: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Wrapped template kind — `"AgentTemplate"`, `"AutomationTemplate"`, `"AgentRoutineTemplate"`, `"AgentToolTemplate"`, `"AgentComputerTemplate"`, or `"SolutionTemplateRef"` for ref-mode bundles. + pub template_kind: Option, + /// Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references. + pub templates: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the Solution config was last modified (ISO 8601). + pub updated_at: Option>, + /// `true` when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always `false` for system-only rows. + pub upgrade_available: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The stable virtual path assigned to this Solution config, used as the deduplication key when the same Solution appears under multiple owner scopes. `null` when unset. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionTemplate { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this template config was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Description of the template from the config body. `null` if the current version has no `description` field. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name from the config body. `null` if the current version has no `display_name` field. + pub display_name: Option, + /// Template config ID (`cfg_...`). + pub id: String, + /// Config kind identifier for this template (e.g. `"agent_tool_template"`). + pub kind: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable lookup key assigned to this template config. `null` if no lookup key is set. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Template name as stored in the config body. `null` if the current version has no `name` field. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this template config was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Virtual filesystem path for this template config. `null` if not set. + pub virtual_path: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolution { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Summary of the current parent Solution config row. `solution` is the pinned Solution version the agent points at; `current_solution` is the source Solution config row as it exists now. + pub current_solution: Option, + /// Summary of the parent Solution, including `upgrade_available`, `latest_version`, and `latest_solution` when a newer system-scoped version is available for the agent's org-scoped Solution. + pub solution: GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionSolution, + /// Summary of the AgentTemplate config (`cfg_...`) the agent was last provisioned or updated from. + pub template: GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItemSourceSolutionTemplate, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemParticipatingAgentsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Access control list for the agent. Contains a `grants` array where each entry specifies `principal_type`, `principal`, and `actions`. `null` when no ACL restrictions are applied and the agent is accessible to all members of its scope. + pub acl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the application that owns this agent (`dap_...`). + pub app: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the agent was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Default LLM model identifier used by this agent when no model is specified at runtime (e.g. `"claude-3-7-sonnet-latest"`). + pub default_model: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of what the agent does. `null` if not set. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Email address provisioned for this agent. `null` if email delivery is not configured. + pub email: Option, + /// Agent ID (`agi_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// System-level identity prompt that shapes the agent's persona and behavior. + pub identity: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the AgentTemplate config (`cfg_...`) this agent was last provisioned or updated from. `null` for manually created agents. + pub last_applied_template_config: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Stable, user-defined identifier for this agent within the application. Unique per app. + pub lookup_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the agent. Not interpreted by the platform. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable display name for the agent. `null` if not set. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this agent belongs to (`org_...`). `null` if the agent is not org-scoped. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the organization this agent belongs to. `null` when the agent is not org-scoped or when the org association was not preloaded. + pub org_name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Free-form label identifying the source or author that created this agent (e.g. a username or pipeline name). + pub originator: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Phone number provisioned for this agent. `null` if SMS is not configured. + pub phone_number: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the sandbox environment this agent is scoped to (`dsb_...`). `null` in production deployments. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Source Solution and AgentTemplate summary for agents provisioned from a Solution. Includes `upgrade_available`, `latest_version`, and `latest_solution` so you can render an upgrade badge without a separate dry-run call. `null` for hand-built agents and agents whose tracked template or parent Solution has been deleted. Populated only on single-agent GET responses, never on list endpoints. + pub source_solution: + Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this agent (`tem_...`). `null` if the agent is not team-scoped. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// True when the agent's last-applied template version is behind the current version of its AgentTemplate config — i.e. reapplying the template (a per-agent upgrade) would bring it newer Solution content. Self-clears once the agent is reapplied. Computed on both the list endpoints and single-agent GET. Distinct from `source_solution.upgrade_available`, which compares Solution *versions*: an agent can lag its template (`template_upgrade_available: true`) while the org already holds the latest Solution version (`upgrade_available: false`). + pub template_upgrade_available: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the agent was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user that owns this agent (`usr_...`). `null` if the agent is not user-scoped. + pub user: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItemSettings { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured. + pub agent_enabled: Option, +} + +/// Contract-defined alternatives for GetApiV1UsersUserThreadsResponseDataItemCreator. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetApiV1UsersUserThreadsResponseDataItemCreator { + /// Variant1 union variant. + Variant1(String), + /// Variant2 union variant. + Variant2(Value), +} + +/// Contract-defined values for GetApiV1UsersUserThreadsResponseDataItemVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1UsersUserThreadsResponseDataItemVisibility { + /// The team wire value. + #[serde(rename = "team")] + Team, + /// The restricted wire value. + #[serde(rename = "restricted")] + Restricted, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the agent that owns this thread (`agt_...`). `null` for user-owned or team-owned threads. + pub agent_user: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the thread was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// User who created this thread. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if the creator is unknown. + pub creator: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional description or purpose statement for the thread. `null` if not set. + pub description: Option, + /// Thread ID (`thr_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this thread operates as a channel — a multi-member broadcast-style conversation. + pub is_channel: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this is the default thread for its owner. Each user or team has at most one default thread. + pub is_default: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this thread is ephemeral and may be deleted automatically after a period of inactivity or when its TTL expires. + pub is_transient: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether this thread is hidden from public discovery. Unlisted threads are accessible only to direct participants. + pub is_unlisted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Application-defined stable key that uniquely identifies the thread within its scope. Useful for idempotent creation. `null` if not set. + pub key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Thread subtype: `"standard"` for ordinary threads, `"slack_mirror"` for the membership-strict mirror of a Slack channel, `"slashwork_mirror"` for the membership-strict mirror of a Slashwork group. Read-only — derived server-side at creation, never accepted from params. + pub kind: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the most recent message was posted in this thread, falling back to the thread's creation time if it has no messages. Always populated on thread list endpoints (which order by it, after default threads); `null` on endpoints that don't compute activity enrichment. + pub last_activity: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Single-line snippet of the most recent message's text content (first non-empty line, truncated to 140 characters). Populated on thread list endpoints alongside `last_activity`; `null` when the thread has no messages, the latest message has no text content (e.g. attachment-only), or the endpoint doesn't compute activity enrichment. + pub last_message_preview: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name of the sender of the most recent message — the same message `last_message_preview` snippets. Populated on thread list endpoints; `null` when the thread has no messages or the endpoint doesn't compute activity enrichment. + pub last_message_sender: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value metadata attached to the thread. Shape is application-defined; `null` if no metadata has been set. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether the authenticated user has muted notifications for this thread. `true` suppresses all notification delivery. + pub muted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization this thread belongs to (`org_...`). `null` for threads outside an org context. + pub org: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The message that spawned this thread as a sub-thread. `null` for top-level threads. + pub parent_message: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Array of participant user IDs (`usr_...`) who are members of this thread. + pub participant: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Expanded participant user objects for each member of this thread. Populated only when the association is loaded. + pub participants: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Composite actor identifiers for all participants currently active in this thread. Present only when actor enrichment is requested. + pub participating_actor: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Expanded agent objects for all agents participating in this thread. Present only when agent enrichment is requested. + pub participating_agents: + Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// The authenticated user's membership role in this thread, e.g. `"owner"`, `"member"`, or `"viewer"`. `null` if the user is not a member. + pub role: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the developer sandbox this thread is scoped to (`dsb_...`). `null` for production threads. + pub sandbox: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Per-thread configuration settings controlling AI agent behavior for this thread. + pub settings: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// URL-safe slug for the thread, used in human-readable permalinks. `null` if not assigned. + pub slug: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Threads that are nested under this thread as replies to a parent message. Present only when sub-thread enrichment is requested. + pub sub_threads: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Status tags on the thread (e.g. `"blocked"`, `"needs-review"`). Edited by any thread participant via the `/threads/:thread/tags` endpoints and filterable on the thread list endpoints. Empty array if none set. + pub tags: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the team that owns this thread (`team_...`). `null` for user-owned or agent-owned threads. + pub team: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable name of the thread. `null` if no title has been set. + pub title: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Time-to-live in seconds after which the thread may be automatically cleaned up. `null` if the thread does not expire. + pub ttl: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of messages in this thread that the authenticated user has not yet read. Present only when read-state enrichment is requested. + pub unread_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the thread was last modified (ISO 8601). + pub updated_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the user who owns this thread (`usr_...`). `null` for team-owned or agent-owned threads. + pub user: Option, + /// Who can read the thread: `team` for every owning-team member, `restricted` for team-readable threads with an explicit roster, or `private` for roster-only access. + pub visibility: GetApiV1UsersUserThreadsResponseDataItemVisibility, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserThreadsResponse { + /// Array of thread objects matching the requested filters and agent narrowings. + pub data: Vec, +} + +/// Contract-defined values for PostApiV1UsersUserThreadsInputThreadMembersItemType. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum PostApiV1UsersUserThreadsInputThreadMembersItemType { + /// The user wire value. + #[serde(rename = "user")] + User, + /// The agent wire value. + #[serde(rename = "agent")] + Agent, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1UsersUserThreadsInputThreadMembersItem { + /// Public user (`usr_...`) or agent (`agt_...`) ID matching `type`. + pub id: String, + #[serde(rename = "type")] + /// Member kind. Use `user` for a user ID or `agent` for an agent ID. + pub type_: PostApiV1UsersUserThreadsInputThreadMembersItemType, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1UsersUserThreadsInputThreadProfilePicture { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Base64-encoded image bytes. + pub data: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Original filename of the uploaded image, used for display and content-type inference. + pub filename: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. + pub mime_type: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1UsersUserThreadsInputThreadSettings { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured. + pub agent_enabled: Option, +} + +/// Contract-defined values for PostApiV1UsersUserThreadsInputThreadVisibility. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum PostApiV1UsersUserThreadsInputThreadVisibility { + /// The team wire value. + #[serde(rename = "team")] + Team, + /// The restricted wire value. + #[serde(rename = "restricted")] + Restricted, + /// The private wire value. + #[serde(rename = "private")] + Private, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1UsersUserThreadsInputThread { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, provisions a legacy chat agent alongside the thread. Only needed for integrations that depend on the pre-v2 agent model. + pub create_legacy_agent: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional longer description of the thread's purpose. `null` if not provided. + pub description: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, the thread is hidden from the default thread list and accessible only by direct link or ID. + pub is_unlisted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Client-assigned unique key for idempotent creation or later lookup. Must be unique within the owning organization. + pub key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Users and agents to add atomically when the thread is created. Each target must pass the same authorization rules as a post-creation member add. Slack mirror threads reject non-empty caller-supplied rosters because their membership is sync-owned. + pub members: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Arbitrary key-value pairs stored alongside the thread. Values must be strings or numbers. + pub metadata: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, push and in-app notifications for this thread are suppressed for the creating user. + pub muted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// ID of the organization to create the thread under. Defaults to the authenticated user's primary organization when omitted. + pub org_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional profile image for the thread, provided as a base64-encoded payload. + pub profile_picture: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Configuration overrides for the thread, such as AI model selection and context window settings. + pub settings: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional URL-safe identifier. Derived from the title when omitted and unique within the thread owner. + pub slug: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Display name for the thread. `null` if omitted, which causes the thread to be untitled. + pub title: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Thread visibility. A team-owned thread with members must explicitly use `restricted` or `private`. User- and agent-owned threads with members default to `private` and reject every other value. + pub visibility: Option, +} + +/// Creates a new thread owned by the specified user. The authenticated caller must +/// have access to the target user's account; a 403 is returned otherwise. +/// +/// An automatic welcome message is sent into the thread upon creation unless +/// `skip_welcome_message` is set to `true`. The thread is immediately visible to +/// the owning user and any members added at creation time. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1UsersUserThreadsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When `true`, suppresses the automatic welcome message that is otherwise sent into the thread on creation. Defaults to `false`. + pub skip_welcome_message: Option, + /// Attributes for the new thread. See ThreadCreateParams for the full set of accepted fields. + pub thread: PostApiV1UsersUserThreadsInputThread, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTokensResponseDataItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this token was created (ISO 8601). + pub created_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When the token expires. `null` on legacy rows that predate stored expiry. + pub expires_at: Option>, + /// Token ID (`sat_...`). + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this token was last used to authenticate a request. `null` if the token has never been used. + pub last_used_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable label assigned to this token at creation time. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// When this token was revoked. `null` if the token is still active. + pub revoked_at: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Space-separated OAuth scopes stamped on the token. `null` on legacy rows; treat as `full_access`. + pub scopes: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Raw bearer token string. Present only in the response to the create request; never returned again after that. + pub token: Option, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1UsersUserTokensResponse { + /// Array of access token objects. Raw JWT values are not included. + pub data: Vec, +} + +/// Issues a new long-lived access token for the authenticated user. The raw +/// JWT is returned in the `token` field of the response exactly once and +/// cannot be retrieved again — store it securely immediately after creation. +/// +/// `scopes` is optional. When omitted the token receives `full_access`. +/// Known catalog scopes (for example `profile`) restrict the token through +/// the same `ScopeGuard` used by OAuth. +/// +/// `expires_in_days` is optional and must be one of `7`, `30`, `60`, `90`, +/// or `365`. When omitted the token lasts 30 days. Each user may hold at +/// most 50 active tokens; exceeding that limit returns 429. +/// +/// The caller must be the user identified by `user` and must present a +/// first-party session (or a `full_access` access token). A restricted +/// access token cannot mint another token. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1UsersUserTokensInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Lifetime in days. One of `7`, `30`, `60`, `90`, or `365`. Defaults to `30`. + pub expires_in_days: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable label for the token (e.g. `"Codex MCP"`). Stored as metadata only. + pub name: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional OAuth scopes to stamp on the token. Omit for `full_access`. + pub scopes: Option>, +} + +/// Query parameters for get_api_v1_work_items. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1WorkItemsParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional durable execution ID filter. + pub execution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum work items per page. Defaults to 50; maximum is 100. + pub limit: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque cursor for the next page of older queued work. + pub after_cursor: Option, +} + +/// Atomically records command failure, marks the work item failed, and either +/// wakes the workflow at the node's error edge or fails the owning run when no +/// error edge exists. Retrying the same lease and error is idempotent; a +/// different terminal payload conflicts. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1WorkItemsWorkItemFailInput { + /// JSON-serializable failure returned by the worker. + pub error: std::collections::BTreeMap, + /// Saved lease token. + pub lease_owner: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1WorkItemsWorkItemHeartbeatInput { + /// Saved lease token. + pub lease_owner: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Replacement lease duration from 15 through 3600 seconds. Defaults to 300. + pub lease_seconds: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1WorkItemsWorkItemStartInput { + /// Saved lease token. + pub lease_owner: String, +} + +/// Atomically records the command completion, marks the work item succeeded, +/// advances the journal sequence, and enqueues the owning workflow continuation. +/// Retrying the same lease and result is idempotent; a different result conflicts. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1WorkItemsWorkItemSubmitInput { + /// Saved lease token. + pub lease_owner: String, + /// JSON-serializable output returned to the workflow. + pub result: std::collections::BTreeMap, +} + +/// Contract-defined values for GetApiV1AiChatModelsResponseDataItemCapabilitiesItem. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1AiChatModelsResponseDataItemCapabilitiesItem { + /// The image wire value. + #[serde(rename = "image")] + Image, + /// The search wire value. + #[serde(rename = "search")] + Search, + /// The thinking wire value. + #[serde(rename = "thinking")] + Thinking, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AiChatModelsResponseDataItem { + /// Machine-readable model capabilities. `"image"` marks image-input chat, `"search"` marks built-in web search, and `"thinking"` marks models with configurable reasoning. Empty when the catalog entry declares no special capabilities. + pub capabilities: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum context-window size in tokens this model accepts, when the platform publishes it. Use it to size prompt/history against the real window rather than a hardcoded default. `null` for entries whose window the platform does not report (e.g. legacy or mock model listings); clients should apply a conservative fallback in that case. + pub context_window: Option>, + /// `true` for the model the platform selects when an agent has no `default_model` configured, or for the system-wide fallback in image-generation contexts. Exactly one entry in any given model list carries this flag. + pub default: bool, + /// Provider-assigned model identifier used when specifying a model on API requests, e.g. `"claude-sonnet-4-6"` or `"gemini-2.5-flash"`. + pub id: String, + /// MIME types accepted in chat `content_parts` image/file inputs for this model. For image-capable chat models this includes values such as `"image/png"`. Empty for text-only models. + pub input_media_formats: Vec, + /// Human-readable display label for this model, e.g. `"Claude Sonnet 4.6"` or `"Gemini 3.5 Flash (thinking)"`. Render this value directly in pickers rather than attempting to parse or transform `id`. Falls back to the `id` string when the catalog entry does not declare an explicit name. + pub name: String, + /// MIME types this model can emit as media in chat responses. Empty for text-output models, including image-understanding models that only return text. + pub output_media_formats: Vec, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AiChatModelsResponse { + /// Array of available model objects. At least one entry is always present. + pub data: Vec, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsInputMessagesItemToolCallsItem { + /// Arguments the model wants to pass to the tool, as a key-value map. Deserialize and validate these against the tool's input schema before executing. + pub arguments: std::collections::BTreeMap, + /// Unique identifier for this tool call, assigned by the model. Use this value as `id` when submitting the corresponding tool result. + pub id: String, + /// Name of the tool or function the model wants to invoke, e.g. `"web_search"` or `"run_code"`. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque signature representing the model's internal reasoning that led to this tool call. `null` when the provider does not expose chain-of-thought data. + pub thought_signature: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsInputMessagesItemToolResultsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Plain-text output produced by the tool execution. `null` when the result is expressed entirely through `resolution`. + pub content: Option, + /// ID of the tool call this result satisfies. Must match the `id` from the corresponding `AIToolCall`. + pub id: String, + /// Name of the tool or function that was executed, e.g. `"web_search"`. Must match the `name` from the corresponding `AIToolCall`. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Structured result data from the tool execution. Shape varies by tool. `null` when the result is expressed as plain text in `content`. + pub resolution: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsInputMessagesItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Plain-text content of the message. Present for `system`, `user`, and `assistant` messages. `null` when the message body is expressed through `content_parts` or `tool_calls`. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Multimodal content parts for the message, used when the body includes images or mixed media. Each part is a map with a `type` key (`"text"`, `"image_url"`, or `"image_data"`). `null` when `content` is set. + pub content_parts: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque token that can be passed on a subsequent request to resume this conversation from the current state. `null` when the provider does not support conversation resumption. + pub resume_token: Option, + /// The speaker role for this message. One of `"system"`, `"user"`, `"assistant"`, or `"tool"`. + pub role: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Parsed structured data returned by the model when a JSON schema or structured-output mode was requested. Shape varies by the schema supplied at call time. `null` when structured output was not requested. + pub structured_output: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Tool calls requested by the model in an `assistant` message. Present only on assistant messages that invoke one or more tools. `null` on all other message roles. + pub tool_calls: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Tool execution results provided in a `tool` message. Each entry corresponds to a prior tool call by its `id`. `null` on all other message roles. + pub tool_results: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsInputOptsToolsItemFunction { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of what the function does. The model uses this to decide when to call the function. `null` if not provided. + pub description: Option, + /// Unique name of the function that the model can invoke, e.g. `"get_weather"`. + pub name: String, + /// JSON Schema object describing the function's accepted parameters. Must be a valid JSON Schema of type `"object"`. + pub parameters: std::collections::BTreeMap, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsInputOptsToolsItem { + /// Callable function this tool exposes, including its name, description, and parameter schema. + pub function: PostApiV1AiChatCompletionsInputOptsToolsItemFunction, + #[serde(rename = "type")] + /// The tool type. Currently always `"function"`. + pub type_: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsInputOpts { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of tokens the model may generate in the completion. Omit to use the model's default limit. + pub max_tokens: Option, + /// Model identifier to use for the completion, e.g. `"gpt-4o"` or `"claude-3-7-sonnet-latest"`. + pub model: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Server-managed tool declarations executed before the response is returned. Each entry must include a `type` key; currently only `"search"` is supported. + pub server_tools: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Native structured-output configuration. Include a `schema` JSON Schema object and optional `name` and `strict` fields. + pub structured_output: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sampling temperature between `0.0` and `2.0`. Higher values produce more random output. Omit to use the model's default. + pub temperature: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Controls how the model selects tools. One of `"auto"`, `"required"`, or `"none"`. Omit to let the model decide. + pub tool_choice: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// OpenAI-compatible tool definitions available to the model. Omit when not using function calling. + pub tools: Option>, +} + +/// Sends a list of messages to the configured AI provider and returns a single +/// completion. Use this endpoint when you want direct, low-level access to the +/// underlying model without any workflow or agent orchestration. +/// +/// The authenticated app must have the `llm_calls` entitlement enabled on its +/// plan. Requests that exceed the plan quota are rejected with `402`. Token +/// usage is recorded against the authenticated app and organization. +/// +/// Supply `tools` and `tool_choice` to enable OpenAI-compatible function +/// calling. Use `server_tools` to activate platform-managed tools such as +/// search that run on the server side before the response is returned. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map used to resolve template variables in message content. Omit if messages contain no templates. + pub context: Option>, + /// Ordered list of conversation messages to send to the model. + pub messages: Vec, + /// Model and sampling configuration for this request. + pub opts: PostApiV1AiChatCompletionsInputOpts, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional UUID grouping this and other completions under one session in the Developers dashboard. Pass the same value across requests to link them; omit to auto-generate a per-request session. + pub session_id: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsStreamInputMessagesItemToolCallsItem { + /// Arguments the model wants to pass to the tool, as a key-value map. Deserialize and validate these against the tool's input schema before executing. + pub arguments: std::collections::BTreeMap, + /// Unique identifier for this tool call, assigned by the model. Use this value as `id` when submitting the corresponding tool result. + pub id: String, + /// Name of the tool or function the model wants to invoke, e.g. `"web_search"` or `"run_code"`. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque signature representing the model's internal reasoning that led to this tool call. `null` when the provider does not expose chain-of-thought data. + pub thought_signature: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsStreamInputMessagesItemToolResultsItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Plain-text output produced by the tool execution. `null` when the result is expressed entirely through `resolution`. + pub content: Option, + /// ID of the tool call this result satisfies. Must match the `id` from the corresponding `AIToolCall`. + pub id: String, + /// Name of the tool or function that was executed, e.g. `"web_search"`. Must match the `name` from the corresponding `AIToolCall`. + pub name: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Structured result data from the tool execution. Shape varies by tool. `null` when the result is expressed as plain text in `content`. + pub resolution: Option, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsStreamInputMessagesItem { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Plain-text content of the message. Present for `system`, `user`, and `assistant` messages. `null` when the message body is expressed through `content_parts` or `tool_calls`. + pub content: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Multimodal content parts for the message, used when the body includes images or mixed media. Each part is a map with a `type` key (`"text"`, `"image_url"`, or `"image_data"`). `null` when `content` is set. + pub content_parts: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Opaque token that can be passed on a subsequent request to resume this conversation from the current state. `null` when the provider does not support conversation resumption. + pub resume_token: Option, + /// The speaker role for this message. One of `"system"`, `"user"`, `"assistant"`, or `"tool"`. + pub role: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Parsed structured data returned by the model when a JSON schema or structured-output mode was requested. Shape varies by the schema supplied at call time. `null` when structured output was not requested. + pub structured_output: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Tool calls requested by the model in an `assistant` message. Present only on assistant messages that invoke one or more tools. `null` on all other message roles. + pub tool_calls: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Tool execution results provided in a `tool` message. Each entry corresponds to a prior tool call by its `id`. `null` on all other message roles. + pub tool_results: Option>, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsStreamInputOptsToolsItemFunction { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Human-readable description of what the function does. The model uses this to decide when to call the function. `null` if not provided. + pub description: Option, + /// Unique name of the function that the model can invoke, e.g. `"get_weather"`. + pub name: String, + /// JSON Schema object describing the function's accepted parameters. Must be a valid JSON Schema of type `"object"`. + pub parameters: std::collections::BTreeMap, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsStreamInputOptsToolsItem { + /// Callable function this tool exposes, including its name, description, and parameter schema. + pub function: PostApiV1AiChatCompletionsStreamInputOptsToolsItemFunction, + #[serde(rename = "type")] + /// The tool type. Currently always `"function"`. + pub type_: String, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsStreamInputOpts { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum number of tokens the model may generate. Omit for the model default. + pub max_tokens: Option, + /// Model identifier, e.g. `"gpt-4o"` or `"claude-3-7-sonnet-latest"`. + pub model: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Server-managed tool declarations executed before the response. Each entry must include a `type` key; currently only `"search"` is supported. + pub server_tools: Option>>, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Sampling temperature between `0.0` and `2.0`. Higher values produce more random output. Omit for the model default. + pub temperature: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Controls tool selection. One of `"auto"`, `"required"`, or `"none"`. Omit to let the model decide. + pub tool_choice: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// OpenAI-compatible tool definitions available to the model. Omit when not using function calling. + pub tools: Option>, +} + +/// Streams a chat completion over Server-Sent Events. Emits `thinking_delta` for +/// supported reasoning models, `message_delta`, `message_complete`, +/// `tool_call_*`, `tool_result`, and a terminal `done` (or `error`) event. Same +/// request shape as the non-streaming completion endpoint; the app must have the +/// `llm_calls` entitlement. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiChatCompletionsStreamInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Key-value map used to resolve template variables in message content. Omit if messages contain no templates. + pub context: Option>, + /// Ordered list of conversation messages to send to the model. + pub messages: Vec, + /// Model and sampling configuration for this request. + pub opts: PostApiV1AiChatCompletionsStreamInputOpts, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Optional UUID grouping this and other completions under one session in the Developers dashboard. Pass the same value across requests to link them; omit to auto-generate a per-request session. + pub session_id: Option, +} + +/// Typed events emitted by post_api_v1_ai_chat_completions_stream. +#[derive(Debug, Clone, PartialEq)] +pub enum PostApiV1AiChatCompletionsStreamEvent { + /// Contract-defined stream event. + Done(AIChatStreamDone), + /// Contract-defined stream event. + Error(AIChatStreamError), + /// Contract-defined stream event. + MessageComplete(AIChatStreamMessageComplete), + /// Contract-defined stream event. + MessageDelta(AIChatStreamMessageDelta), + /// Contract-defined stream event. + ThinkingDelta(AIChatStreamThinkingDelta), + /// Contract-defined stream event. + ToolCallDelta(AIChatStreamToolCallDelta), + /// Contract-defined stream event. + ToolResult(AIChatStreamToolResult), +} +impl SseDecode for PostApiV1AiChatCompletionsStreamEvent { + fn decode(event: &str, data: &str) -> Result { + match event { + "done" => Ok(Self::Done(serde_json::from_str(data)?)), + "error" => Ok(Self::Error(serde_json::from_str(data)?)), + "message_complete" => Ok(Self::MessageComplete(serde_json::from_str(data)?)), + "message_delta" => Ok(Self::MessageDelta(serde_json::from_str(data)?)), + "thinking_delta" => Ok(Self::ThinkingDelta(serde_json::from_str(data)?)), + "tool_call_delta" => Ok(Self::ToolCallDelta(serde_json::from_str(data)?)), + "tool_result" => Ok(Self::ToolResult(serde_json::from_str(data)?)), + other => Err(crate::Error::UnknownSseEvent(other.to_owned())), + } + } +} + +/// Embeds both texts in one synchronous request using the platform's default +/// embedding model, then returns their cosine similarity. The score uses the +/// same `1 - cosine_distance` convention as context retrieval. A score near +/// `1.0` indicates similar vector direction; lower scores indicate less similar +/// text. This endpoint is intended for authenticated users interactively +/// exploring how the platform's retrieval similarity behaves. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiEmbeddingSimilarityComparisonInput { + /// First text to embed and compare. + pub text_a: String, + /// Second text to embed and compare. + pub text_b: String, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiEmbeddingSimilarityComparisonResponse { + /// Configured default embedding model key used for both texts. + pub model: String, + /// Cosine similarity from `-1.0` to `1.0`, computed as `1 - cosine_distance`. + pub similarity_score: f64, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiImageEditsInputImagesItem { + /// The raw image content encoded as a base64 string (standard encoding, no line breaks). + pub image_data: String, + /// MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. Must match the actual encoding of `image_data`. + pub image_type: String, +} + +/// Applies a text-guided edit to one or more source images and returns the +/// resulting image. Pass the source images as base64-encoded objects in the +/// `images` array alongside a `prompt` describing the desired modification. +/// +/// The underlying provider is selected by the `model` parameter. Omit `model` +/// to use the platform default. Size, quality, style, and format options are +/// forwarded to the provider as-is; unsupported combinations for a given model +/// return a 422 error with the provider's error message. +/// +/// This endpoint requires authentication. The request is billed against the +/// workspace associated with the authenticated user. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiImageEditsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Desired aspect ratio of the output, e.g. `"1:1"` or `"16:9"`. Not supported by all models; omit to use the model's default. + pub aspect_ratio: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Background treatment for the output. Accepted values and behavior are model-dependent. + pub background: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit output height in pixels. Takes precedence over `size` when both are provided. Not supported by all models. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Output resolution tier for Gemini models, e.g. `"1K"`, `"2K"`, or `"4K"`. Ignored by non-Gemini models. + pub image_size: Option, + /// One or more source images to edit. Each image must be supplied as a base64-encoded object. + pub images: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Model identifier to use for editing. Omit to use the platform default image model. + pub model: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Desired MIME type or format for the returned image. Common values: `"png"`, `"jpeg"`, `"webp"`. Defaults to the model's native format. + pub output_format: Option, + /// Natural-language description of the edit to apply to the source image(s). + pub prompt: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Quality preset for the output image. Accepted values and behavior are model-dependent. + pub quality: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Output dimensions as a WxH string, e.g. `"1024x1024"`. Applies to OpenAI-compatible models. Omit to use the model's default. + pub size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Style preset applied to the edit. Accepted values and behavior are model-dependent. + pub style: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit output width in pixels. Takes precedence over `size` when both are provided. Not supported by all models. + pub width: Option, +} + +/// Generates one or more images from a natural-language `prompt` using the +/// specified AI image model. The response contains the first generated image; +/// use `n` to request additional images (where supported by the model). +/// +/// The underlying provider is selected by the `model` parameter. Omit `model` +/// to use the platform default. Size, quality, style, and format options are +/// forwarded to the provider as-is; unsupported combinations for a given model +/// return a 422 error with the provider's error message. +/// +/// This endpoint requires authentication. The request is billed against the +/// workspace associated with the authenticated user. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostApiV1AiImageGenerationsInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Desired aspect ratio of the output, e.g. `"1:1"` or `"16:9"`. Not supported by all models; omit to use the model's default. + pub aspect_ratio: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Background treatment for the output. Accepted values and behavior are model-dependent. + pub background: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit output height in pixels. Takes precedence over `size` when both are provided. Not supported by all models. + pub height: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Output resolution tier for Gemini models, e.g. `"1K"`, `"2K"`, or `"4K"`. Ignored by non-Gemini models. + pub image_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Model identifier to use for generation. Omit to use the platform default image model. + pub model: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Number of images to generate. Defaults to `1`. Values greater than `1` are only supported by models that allow batch generation. + pub n: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Desired MIME type or format for the returned image. Common values: `"png"`, `"jpeg"`, `"webp"`. Defaults to the model's native format. + pub output_format: Option, + /// Natural-language description of the image to generate. + pub prompt: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Quality preset for the output image. Accepted values and behavior are model-dependent. + pub quality: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Output dimensions as a WxH string, e.g. `"1024x1024"`. Applies to OpenAI-compatible models. Omit to use the model's default. + pub size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Style preset applied to the generated image. Accepted values and behavior are model-dependent. + pub style: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Explicit output width in pixels. Takes precedence over `size` when both are provided. Not supported by all models. + pub width: Option, +} + +/// Contract-defined values for GetApiV1AiImageModelsResponseDataItemCapabilitiesItem. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum GetApiV1AiImageModelsResponseDataItemCapabilitiesItem { + /// The image wire value. + #[serde(rename = "image")] + Image, + /// The search wire value. + #[serde(rename = "search")] + Search, + /// The thinking wire value. + #[serde(rename = "thinking")] + Thinking, +} + +/// Generated from the ArchAstro OpenAPI contract. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AiImageModelsResponseDataItem { + /// Machine-readable model capabilities. `"image"` marks image-input chat, `"search"` marks built-in web search, and `"thinking"` marks models with configurable reasoning. Empty when the catalog entry declares no special capabilities. + pub capabilities: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Maximum context-window size in tokens this model accepts, when the platform publishes it. Use it to size prompt/history against the real window rather than a hardcoded default. `null` for entries whose window the platform does not report (e.g. legacy or mock model listings); clients should apply a conservative fallback in that case. + pub context_window: Option>, + /// `true` for the model the platform selects when an agent has no `default_model` configured, or for the system-wide fallback in image-generation contexts. Exactly one entry in any given model list carries this flag. + pub default: bool, + /// Provider-assigned model identifier used when specifying a model on API requests, e.g. `"claude-sonnet-4-6"` or `"gemini-2.5-flash"`. + pub id: String, + /// MIME types accepted in chat `content_parts` image/file inputs for this model. For image-capable chat models this includes values such as `"image/png"`. Empty for text-only models. + pub input_media_formats: Vec, + /// Human-readable display label for this model, e.g. `"Claude Sonnet 4.6"` or `"Gemini 3.5 Flash (thinking)"`. Render this value directly in pickers rather than attempting to parse or transform `id`. Falls back to the `id` string when the catalog entry does not declare an explicit name. + pub name: String, + /// MIME types this model can emit as media in chat responses. Empty for text-output models, including image-understanding models that only return text. + pub output_media_formats: Vec, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetApiV1AiImageModelsResponse { + /// Array of available image generation models, including their identifiers, human-readable names, and which one is the platform default. + pub data: Vec, +} + +/// Successful response +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetOauthScopesResponse { + /// Map of scope name to its definition object. Each key is a scope string (e.g. `"threads:read"`) and each value describes the scope's purpose and requirements. + pub scopes: std::collections::BTreeMap, +} + +/// Issues an access token and a refresh token in exchange for a valid grant. +/// Three grant types are supported: `"authorization_code"`, `"refresh_token"`, +/// and `"urn:ietf:params:oauth:grant-type:device_code"`. +/// +/// For `"authorization_code"` grants, supply `code`, `client`, `redirect_uri`, and +/// optionally `code_verifier` for PKCE flows. Each authorization code is single-use; +/// consuming it a second time returns `invalid_grant`. +/// +/// For `"refresh_token"` grants, supply `refresh_token`. The endpoint rotates the +/// refresh token on every call and returns a fresh pair of tokens. +/// +/// For device-code grants, supply `device_code` and `client`. Poll this endpoint +/// after receiving `authorization_pending` until the user approves or the code +/// expires. Slow down polling if you receive `slow_down`. +/// +/// This endpoint is rate-limited to 20 requests per IP per 60 seconds. Exceeding +/// the limit returns HTTP 429 with `"error": "too_many_requests"`. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostOauthTokenInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// OAuth client ID identifying the application requesting tokens. Required for `"authorization_code"` and device-code grants. + pub client: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Single-use authorization code issued by the authorization endpoint. Required for `"authorization_code"` grants. + pub code: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// PKCE code verifier corresponding to the `code_challenge` sent in the authorization request. Required when the authorization code was issued with a code challenge; omit otherwise. + pub code_verifier: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Device code received from the device authorization endpoint. Required for device-code grants. + pub device_code: Option, + /// The OAuth 2.0 grant type. One of `"authorization_code"`, `"refresh_token"`, or `"urn:ietf:params:oauth:grant-type:device_code"`. + pub grant_type: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Redirect URI that was used in the original authorization request. Must exactly match the URI on record for the client. Required for `"authorization_code"` grants. + pub redirect_uri: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Refresh token received from a previous token response. Required for `"refresh_token"` grants. The token is rotated on each successful call. + pub refresh_token: Option, +} + +/// Grants the pending device authorization identified by `user_code`, completing +/// the OAuth Device Authorization flow on behalf of the authenticated user. Once +/// approved, the device can exchange the `device_code` for an access token. +/// +/// Requires a valid user session — the request must be authenticated as an end +/// user, not a machine client. The `user_code` must belong to a pending (not +/// expired, not already approved or denied) authorization associated with the +/// calling app. +/// +/// If the requested scopes include a `thread`-scoped permission, you must supply +/// the `thread` parameter; omitting it returns a 400 with `error: "invalid_scope"`. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostOauthDeviceApproveInput { + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Thread ID (`thr_...`) to bind to the authorization. Required when the requested scopes include a thread-scoped permission. + pub thread: Option, + /// User-facing verification code shown on the device. Identifies the pending authorization to approve. + pub user_code: String, +} + +/// Query parameters for get_oauth_device_authorization. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct GetOauthDeviceAuthorizationParams { + /// User-facing device authorization code. + pub code: String, +} + +/// Starts the OAuth 2.0 Device Authorization flow for a device that cannot +/// perform browser-based redirects. Returns a `device_code` (used by the device +/// to poll for a token) and a `user_code` (shown to the user to enter at the +/// `verification_uri`). +/// +/// This endpoint requires a publishable API key; secret keys are rejected with +/// a 403. Third-party OAuth must be enabled on the app; if it is not, the +/// response returns `error: "third_party_oauth_not_enabled"` with a 403. +/// +/// The endpoint is rate-limited to 10 requests per IP per minute. Excess +/// requests receive a 429 response. The returned codes expire after +/// `expires_in` seconds; once expired, a new authorization request must be +/// initiated. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostOauthDeviceAuthorizeInput { + /// OAuth client ID (`cli_...`) identifying the application requesting authorization. + pub client: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + /// Space-separated list of OAuth scopes to request, e.g. `"read write"`. Omit to request only the default scopes configured for the client. + pub scope: Option, +} + +/// Rejects the pending device authorization identified by `user_code`, preventing +/// the device from obtaining an access token. Once denied, the device will +/// receive an `access_denied` error on its next token poll. +/// +/// Requires a valid user session. The `user_code` must belong to a pending +/// authorization associated with the calling app. Attempting to deny an already +/// approved, already denied, or expired authorization returns a 400. +/// +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PostOauthDeviceDenyInput { + /// User-facing verification code shown on the device. Identifies the pending authorization to deny. + pub user_code: String, +} + +/// v1 API namespace. +#[derive(Clone)] +pub struct V1 { + pub(crate) client: Client, +} + +impl V1 { + /// Access the activity_feed resource. + pub fn activity_feed(&self) -> ActivityFeedResource { + ActivityFeedResource { + client: self.client.clone(), + } + } + /// Access the agent_computers resource. + pub fn agent_computers(&self) -> AgentComputersResource { + AgentComputersResource { + client: self.client.clone(), + } + } + /// Access the agent_env_vars resource. + pub fn agent_env_vars(&self) -> AgentEnvVarsResource { + AgentEnvVarsResource { + client: self.client.clone(), + } + } + /// Access the agent_health_actions resource. + pub fn agent_health_actions(&self) -> AgentHealthActionsResource { + AgentHealthActionsResource { + client: self.client.clone(), + } + } + /// Access the agent_installations resource. + pub fn agent_installations(&self) -> AgentInstallationsResource { + AgentInstallationsResource { + client: self.client.clone(), + } + } + /// Access the agent_routine_runs resource. + pub fn agent_routine_runs(&self) -> AgentRoutineRunsResource { + AgentRoutineRunsResource { + client: self.client.clone(), + } + } + /// Access the agent_routines resource. + pub fn agent_routines(&self) -> AgentRoutinesResource { + AgentRoutinesResource { + client: self.client.clone(), + } + } + /// Access the agent_sessions resource. + pub fn agent_sessions(&self) -> AgentSessionsResource { + AgentSessionsResource { + client: self.client.clone(), + } + } + /// Access the agent_skills resource. + pub fn agent_skills(&self) -> AgentSkillsResource { + AgentSkillsResource { + client: self.client.clone(), + } + } + /// Access the agent_tools resource. + pub fn agent_tools(&self) -> AgentToolsResource { + AgentToolsResource { + client: self.client.clone(), + } + } + /// Access the agents resource. + pub fn agents(&self) -> AgentsResource { + AgentsResource { + client: self.client.clone(), + } + } + /// Access the artifacts resource. + pub fn artifacts(&self) -> ArtifactsResource { + ArtifactsResource { + client: self.client.clone(), + } + } + /// Access the automation_runs resource. + pub fn automation_runs(&self) -> AutomationRunsResource { + AutomationRunsResource { + client: self.client.clone(), + } + } + /// Access the automations resource. + pub fn automations(&self) -> AutomationsResource { + AutomationsResource { + client: self.client.clone(), + } + } + /// Access the bug_reports resource. + pub fn bug_reports(&self) -> BugReportsResource { + BugReportsResource { + client: self.client.clone(), + } + } + /// Access the config resource. + pub fn config(&self) -> ConfigResource { + ConfigResource { + client: self.client.clone(), + } + } + /// Access the custom_objects resource. + pub fn custom_objects(&self) -> CustomObjectsResource { + CustomObjectsResource { + client: self.client.clone(), + } + } + /// Access the extractions resource. + pub fn extractions(&self) -> ExtractionsResource { + ExtractionsResource { + client: self.client.clone(), + } + } + /// Access the files resource. + pub fn files(&self) -> FilesResource { + FilesResource { + client: self.client.clone(), + } + } + /// Access the installation_sources resource. + pub fn installation_sources(&self) -> InstallationSourcesResource { + InstallationSourcesResource { + client: self.client.clone(), + } + } + /// Access the invites resource. + pub fn invites(&self) -> InvitesResource { + InvitesResource { + client: self.client.clone(), + } + } + /// Access the knowledge_documents resource. + pub fn knowledge_documents(&self) -> KnowledgeDocumentsResource { + KnowledgeDocumentsResource { + client: self.client.clone(), + } + } + /// Access the knowledge_ingestions resource. + pub fn knowledge_ingestions(&self) -> KnowledgeIngestionsResource { + KnowledgeIngestionsResource { + client: self.client.clone(), + } + } + /// Access the knowledge_sources resource. + pub fn knowledge_sources(&self) -> KnowledgeSourcesResource { + KnowledgeSourcesResource { + client: self.client.clone(), + } + } + /// Access the kv resource. + pub fn kv(&self) -> KvResource { + KvResource { + client: self.client.clone(), + } + } + /// Access the notification_preferences resource. + pub fn notification_preferences(&self) -> NotificationPreferencesResource { + NotificationPreferencesResource { + client: self.client.clone(), + } + } + /// Access the notifications resource. + pub fn notifications(&self) -> NotificationsResource { + NotificationsResource { + client: self.client.clone(), + } + } + /// Access the orgs resource. + pub fn orgs(&self) -> OrgsResource { + OrgsResource { + client: self.client.clone(), + } + } + /// Access the private_service_definitions resource. + pub fn private_service_definitions(&self) -> PrivateServiceDefinitionsResource { + PrivateServiceDefinitionsResource { + client: self.client.clone(), + } + } + /// Access the private_service_enrollments resource. + pub fn private_service_enrollments(&self) -> PrivateServiceEnrollmentsResource { + PrivateServiceEnrollmentsResource { + client: self.client.clone(), + } + } + /// Access the private_services resource. + pub fn private_services(&self) -> PrivateServicesResource { + PrivateServicesResource { + client: self.client.clone(), + } + } + /// Access the sandboxes resource. + pub fn sandboxes(&self) -> SandboxesResource { + SandboxesResource { + client: self.client.clone(), + } + } + /// Access the slack_channel_bindings resource. + pub fn slack_channel_bindings(&self) -> SlackChannelBindingsResource { + SlackChannelBindingsResource { + client: self.client.clone(), + } + } + /// Access the solution_categories resource. + pub fn solution_categories(&self) -> SolutionCategoriesResource { + SolutionCategoriesResource { + client: self.client.clone(), + } + } + /// Access the solution_instances resource. + pub fn solution_instances(&self) -> SolutionInstancesResource { + SolutionInstancesResource { + client: self.client.clone(), + } + } + /// Access the solution_tags resource. + pub fn solution_tags(&self) -> SolutionTagsResource { + SolutionTagsResource { + client: self.client.clone(), + } + } + /// Access the solutions resource. + pub fn solutions(&self) -> SolutionsResource { + SolutionsResource { + client: self.client.clone(), + } + } + /// Access the status resource. + pub fn status(&self) -> StatusResource { + StatusResource { + client: self.client.clone(), + } + } + /// Access the tasks resource. + pub fn tasks(&self) -> TasksResource { + TasksResource { + client: self.client.clone(), + } + } + /// Access the team_memberships resource. + pub fn team_memberships(&self) -> TeamMembershipsResource { + TeamMembershipsResource { + client: self.client.clone(), + } + } + /// Access the teams resource. + pub fn teams(&self) -> TeamsResource { + TeamsResource { + client: self.client.clone(), + } + } + /// Access the thread_messages resource. + pub fn thread_messages(&self) -> ThreadMessagesResource { + ThreadMessagesResource { + client: self.client.clone(), + } + } + /// Access the threads resource. + pub fn threads(&self) -> ThreadsResource { + ThreadsResource { + client: self.client.clone(), + } + } + /// Access the trajectories resource. + pub fn trajectories(&self) -> TrajectoriesResource { + TrajectoriesResource { + client: self.client.clone(), + } + } + /// Access the users resource. + pub fn users(&self) -> UsersResource { + UsersResource { + client: self.client.clone(), + } + } + /// Access the work_items resource. + pub fn work_items(&self) -> WorkItemsResource { + WorkItemsResource { + client: self.client.clone(), + } + } + /// Access the ai resource. + pub fn ai(&self) -> AiResource { + AiResource { + client: self.client.clone(), + } + } + /// Access the oauth resource. + pub fn oauth(&self) -> OauthResource { + OauthResource { + client: self.client.clone(), + } + } +} + +/// activity_feed API resource. +#[derive(Clone)] +pub struct ActivityFeedResource { + client: Client, +} + +impl ActivityFeedResource { + /// List activity feed entries + pub async fn list( + &self, + params: Option<&GetApiV1ActivityFeedParams>, + ) -> Result { + let path = "/api/v1/activity_feed".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1ActivityFeedParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } +} + +/// agent_computers API resource. +#[derive(Clone)] +pub struct AgentComputersResource { + client: Client, +} + +impl AgentComputersResource { + /// Delete a computer + pub async fn delete(&self, computer: &str) -> Result<()> { + let mut path = "/api/v1/agent_computers/{computer}".to_owned(); + path = path.replace("{computer}", &crate::encode_path(computer)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, computer: &str) -> Result<()> { + crate::blocking::block_on(self.delete(computer)) + } + /// Retrieve a computer + pub async fn get(&self, computer: &str) -> Result { + let mut path = "/api/v1/agent_computers/{computer}".to_owned(); + path = path.replace("{computer}", &crate::encode_path(computer)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, computer: &str) -> Result { + crate::blocking::block_on(self.get(computer)) + } + /// Execute a command on a computer + pub async fn exec( + &self, + computer: &str, + body: &PostApiV1AgentComputersComputerExecInput, + ) -> Result { + let mut path = "/api/v1/agent_computers/{computer}/exec".to_owned(); + path = path.replace("{computer}", &crate::encode_path(computer)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::exec]. + #[cfg(feature = "blocking")] + pub fn exec_blocking( + &self, + computer: &str, + body: &PostApiV1AgentComputersComputerExecInput, + ) -> Result { + crate::blocking::block_on(self.exec(computer, body)) + } + /// Refresh a computer's status + pub async fn refresh(&self, computer: &str) -> Result { + let mut path = "/api/v1/agent_computers/{computer}/refresh".to_owned(); + path = path.replace("{computer}", &crate::encode_path(computer)); + let request = self.client.request(Method::POST, &path); + request.send().await + } + /// Blocking variant of [Self::refresh]. + #[cfg(feature = "blocking")] + pub fn refresh_blocking(&self, computer: &str) -> Result { + crate::blocking::block_on(self.refresh(computer)) + } +} + +/// agent_env_vars API resource. +#[derive(Clone)] +pub struct AgentEnvVarsResource { + client: Client, +} + +impl AgentEnvVarsResource { + /// Delete an agent environment variable + pub async fn delete(&self, env_var: &str) -> Result<()> { + let mut path = "/api/v1/agent_env_vars/{env_var}".to_owned(); + path = path.replace("{env_var}", &crate::encode_path(env_var)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, env_var: &str) -> Result<()> { + crate::blocking::block_on(self.delete(env_var)) + } + /// Retrieve an agent environment variable + pub async fn get(&self, env_var: &str) -> Result { + let mut path = "/api/v1/agent_env_vars/{env_var}".to_owned(); + path = path.replace("{env_var}", &crate::encode_path(env_var)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, env_var: &str) -> Result { + crate::blocking::block_on(self.get(env_var)) + } + /// Update an agent environment variable + pub async fn update( + &self, + env_var: &str, + body: &PatchApiV1AgentEnvVarsEnvVarInput, + ) -> Result { + let mut path = "/api/v1/agent_env_vars/{env_var}".to_owned(); + path = path.replace("{env_var}", &crate::encode_path(env_var)); + let request = self.client.request(Method::PATCH, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::update]. + #[cfg(feature = "blocking")] + pub fn update_blocking( + &self, + env_var: &str, + body: &PatchApiV1AgentEnvVarsEnvVarInput, + ) -> Result { + crate::blocking::block_on(self.update(env_var, body)) + } +} + +/// agent_health_actions API resource. +#[derive(Clone)] +pub struct AgentHealthActionsResource { + client: Client, +} + +impl AgentHealthActionsResource { + /// Retrieve a health action + pub async fn get(&self, health_action: &str) -> Result { + let mut path = "/api/v1/agent_health_actions/{health_action}".to_owned(); + path = path.replace("{health_action}", &crate::encode_path(health_action)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, health_action: &str) -> Result { + crate::blocking::block_on(self.get(health_action)) + } + /// Verify a health action + pub async fn verify(&self, health_action: &str) -> Result { + let mut path = "/api/v1/agent_health_actions/{health_action}/verify".to_owned(); + path = path.replace("{health_action}", &crate::encode_path(health_action)); + let request = self.client.request(Method::POST, &path); + request.send().await + } + /// Blocking variant of [Self::verify]. + #[cfg(feature = "blocking")] + pub fn verify_blocking(&self, health_action: &str) -> Result { + crate::blocking::block_on(self.verify(health_action)) + } +} + +/// agent_installations API resource. +#[derive(Clone)] +pub struct AgentInstallationsResource { + client: Client, +} + +impl AgentInstallationsResource { + /// Access the nested installation_sources resource. + pub fn installation_sources( + &self, + installation: &str, + ) -> AgentInstallationsInstallationSourcesResource { + AgentInstallationsInstallationSourcesResource { + client: self.client.clone(), + installation: installation.to_owned(), + } + } + /// List installations for an app + pub async fn list( + &self, + params: Option<&GetApiV1AgentInstallationsParams>, + ) -> Result { + let path = "/api/v1/agent_installations".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1AgentInstallationsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Delete an installation + pub async fn delete(&self, installation: &str) -> Result<()> { + let mut path = "/api/v1/agent_installations/{installation}".to_owned(); + path = path.replace("{installation}", &crate::encode_path(installation)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, installation: &str) -> Result<()> { + crate::blocking::block_on(self.delete(installation)) + } + /// Retrieve an installation + pub async fn get(&self, installation: &str) -> Result { + let mut path = "/api/v1/agent_installations/{installation}".to_owned(); + path = path.replace("{installation}", &crate::encode_path(installation)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, installation: &str) -> Result { + crate::blocking::block_on(self.get(installation)) + } + /// Activate an installation + pub async fn activate(&self, installation: &str) -> Result { + let mut path = "/api/v1/agent_installations/{installation}/activate".to_owned(); + path = path.replace("{installation}", &crate::encode_path(installation)); + let request = self.client.request(Method::POST, &path); + request.send().await + } + /// Blocking variant of [Self::activate]. + #[cfg(feature = "blocking")] + pub fn activate_blocking(&self, installation: &str) -> Result { + crate::blocking::block_on(self.activate(installation)) + } + /// Pause an installation + pub async fn pause(&self, installation: &str) -> Result { + let mut path = "/api/v1/agent_installations/{installation}/pause".to_owned(); + path = path.replace("{installation}", &crate::encode_path(installation)); + let request = self.client.request(Method::POST, &path); + request.send().await + } + /// Blocking variant of [Self::pause]. + #[cfg(feature = "blocking")] + pub fn pause_blocking(&self, installation: &str) -> Result { + crate::blocking::block_on(self.pause(installation)) + } + /// Suspend an installation + pub async fn suspend( + &self, + installation: &str, + body: &PostApiV1AgentInstallationsInstallationSuspendInput, + ) -> Result { + let mut path = "/api/v1/agent_installations/{installation}/suspend".to_owned(); + path = path.replace("{installation}", &crate::encode_path(installation)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::suspend]. + #[cfg(feature = "blocking")] + pub fn suspend_blocking( + &self, + installation: &str, + body: &PostApiV1AgentInstallationsInstallationSuspendInput, + ) -> Result { + crate::blocking::block_on(self.suspend(installation, body)) + } +} + +/// installation_sources API resource. +#[derive(Clone)] +pub struct AgentInstallationsInstallationSourcesResource { + client: Client, + /// Bound installation scope. + installation: String, +} + +impl AgentInstallationsInstallationSourcesResource { + /// List sources for an installation + pub async fn list(&self) -> Result { + let mut path = "/api/v1/agent_installations/{installation}/installation_sources".to_owned(); + path = path.replace( + "{installation}", + &crate::encode_path(self.installation.as_str()), + ); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking(&self) -> Result { + crate::blocking::block_on(self.list()) + } + /// Add a source to an installation + pub async fn create( + &self, + body: &PostApiV1AgentInstallationsInstallationInstallationSourcesInput, + ) -> Result { + let mut path = "/api/v1/agent_installations/{installation}/installation_sources".to_owned(); + path = path.replace( + "{installation}", + &crate::encode_path(self.installation.as_str()), + ); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking( + &self, + body: &PostApiV1AgentInstallationsInstallationInstallationSourcesInput, + ) -> Result { + crate::blocking::block_on(self.create(body)) + } +} + +/// agent_routine_runs API resource. +#[derive(Clone)] +pub struct AgentRoutineRunsResource { + client: Client, +} + +impl AgentRoutineRunsResource { + /// List agent routine runs + pub async fn list( + &self, + params: Option<&GetApiV1AgentRoutineRunsParams>, + ) -> Result { + let path = "/api/v1/agent_routine_runs".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1AgentRoutineRunsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Stream agent routine run status + pub async fn stream( + &self, + agent_routine_run: &str, + ) -> Result> { + let mut path = "/api/v1/agent_routine_runs/{agent_routine_run}/stream".to_owned(); + path = path.replace( + "{agent_routine_run}", + &crate::encode_path(agent_routine_run), + ); + let request = self.client.request(Method::GET, &path); + request.stream().await + } +} + +/// agent_routines API resource. +#[derive(Clone)] +pub struct AgentRoutinesResource { + client: Client, +} + +impl AgentRoutinesResource { + /// Access the nested agent_routine_runs resource. + pub fn agent_routine_runs(&self) -> AgentRoutinesAgentRoutineRunsResource { + AgentRoutinesAgentRoutineRunsResource { + client: self.client.clone(), + } + } + /// List routines + pub async fn list( + &self, + params: Option<&GetApiV1AgentRoutinesParams>, + ) -> Result { + let path = "/api/v1/agent_routines".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1AgentRoutinesParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// List routine presets + pub async fn presets(&self) -> Result> { + let path = "/api/v1/agent_routines/presets".to_owned(); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::presets]. + #[cfg(feature = "blocking")] + pub fn presets_blocking(&self) -> Result> { + crate::blocking::block_on(self.presets()) + } + /// Delete a routine + pub async fn delete(&self, routine: &str) -> Result<()> { + let mut path = "/api/v1/agent_routines/{routine}".to_owned(); + path = path.replace("{routine}", &crate::encode_path(routine)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, routine: &str) -> Result<()> { + crate::blocking::block_on(self.delete(routine)) + } + /// Retrieve a routine + pub async fn get(&self, routine: &str) -> Result { + let mut path = "/api/v1/agent_routines/{routine}".to_owned(); + path = path.replace("{routine}", &crate::encode_path(routine)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, routine: &str) -> Result { + crate::blocking::block_on(self.get(routine)) + } + /// Update a routine + pub async fn update( + &self, + routine: &str, + body: &PatchApiV1AgentRoutinesRoutineInput, + ) -> Result { + let mut path = "/api/v1/agent_routines/{routine}".to_owned(); + path = path.replace("{routine}", &crate::encode_path(routine)); + let request = self.client.request(Method::PATCH, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::update]. + #[cfg(feature = "blocking")] + pub fn update_blocking( + &self, + routine: &str, + body: &PatchApiV1AgentRoutinesRoutineInput, + ) -> Result { + crate::blocking::block_on(self.update(routine, body)) + } + /// Activate a routine + pub async fn activate(&self, routine: &str) -> Result { + let mut path = "/api/v1/agent_routines/{routine}/activate".to_owned(); + path = path.replace("{routine}", &crate::encode_path(routine)); + let request = self.client.request(Method::POST, &path); + request.send().await + } + /// Blocking variant of [Self::activate]. + #[cfg(feature = "blocking")] + pub fn activate_blocking(&self, routine: &str) -> Result { + crate::blocking::block_on(self.activate(routine)) + } + /// Invoke a routine + pub async fn invoke( + &self, + routine: &str, + body: &PostApiV1AgentRoutinesRoutineInvokeInput, + ) -> Result { + let mut path = "/api/v1/agent_routines/{routine}/invoke".to_owned(); + path = path.replace("{routine}", &crate::encode_path(routine)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::invoke]. + #[cfg(feature = "blocking")] + pub fn invoke_blocking( + &self, + routine: &str, + body: &PostApiV1AgentRoutinesRoutineInvokeInput, + ) -> Result { + crate::blocking::block_on(self.invoke(routine, body)) + } + /// Pause a routine + pub async fn pause(&self, routine: &str) -> Result { + let mut path = "/api/v1/agent_routines/{routine}/pause".to_owned(); + path = path.replace("{routine}", &crate::encode_path(routine)); + let request = self.client.request(Method::POST, &path); + request.send().await + } + /// Blocking variant of [Self::pause]. + #[cfg(feature = "blocking")] + pub fn pause_blocking(&self, routine: &str) -> Result { + crate::blocking::block_on(self.pause(routine)) + } + /// List runs for a routine + pub async fn runs( + &self, + routine: &str, + params: Option<&GetApiV1AgentRoutinesRoutineRunsParams>, + ) -> Result { + let mut path = "/api/v1/agent_routines/{routine}/runs".to_owned(); + path = path.replace("{routine}", &crate::encode_path(routine)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::runs]. + #[cfg(feature = "blocking")] + pub fn runs_blocking( + &self, + routine: &str, + params: Option<&GetApiV1AgentRoutinesRoutineRunsParams>, + ) -> Result { + crate::blocking::block_on(self.runs(routine, params)) + } +} + +/// agent_routine_runs API resource. +#[derive(Clone)] +pub struct AgentRoutinesAgentRoutineRunsResource { + client: Client, +} + +impl AgentRoutinesAgentRoutineRunsResource { + /// Retrieve a routine run + pub async fn get(&self, run: &str) -> Result { + let mut path = "/api/v1/agent_routines/runs/{run}".to_owned(); + path = path.replace("{run}", &crate::encode_path(run)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, run: &str) -> Result { + crate::blocking::block_on(self.get(run)) + } + /// List a routine run journal + pub async fn journal( + &self, + run: &str, + params: Option<&GetApiV1AgentRoutinesRunsRunJournalParams>, + ) -> Result { + let mut path = "/api/v1/agent_routines/runs/{run}/journal".to_owned(); + path = path.replace("{run}", &crate::encode_path(run)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::journal]. + #[cfg(feature = "blocking")] + pub fn journal_blocking( + &self, + run: &str, + params: Option<&GetApiV1AgentRoutinesRunsRunJournalParams>, + ) -> Result { + crate::blocking::block_on(self.journal(run, params)) + } +} + +/// agent_sessions API resource. +#[derive(Clone)] +pub struct AgentSessionsResource { + client: Client, +} + +impl AgentSessionsResource { + /// List agent sessions + pub async fn list( + &self, + params: Option<&GetApiV1AgentSessionsParams>, + ) -> Result { + let path = "/api/v1/agent_sessions".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1AgentSessionsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create an agent session + pub async fn create(&self, body: &PostApiV1AgentSessionsInput) -> Result { + let path = "/api/v1/agent_sessions".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1AgentSessionsInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Delete an agent session + pub async fn delete(&self, agent_session: &str) -> Result<()> { + let mut path = "/api/v1/agent_sessions/{agent_session}".to_owned(); + path = path.replace("{agent_session}", &crate::encode_path(agent_session)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, agent_session: &str) -> Result<()> { + crate::blocking::block_on(self.delete(agent_session)) + } + /// Retrieve an agent session + pub async fn get(&self, agent_session: &str) -> Result { + let mut path = "/api/v1/agent_sessions/{agent_session}".to_owned(); + path = path.replace("{agent_session}", &crate::encode_path(agent_session)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, agent_session: &str) -> Result { + crate::blocking::block_on(self.get(agent_session)) + } + /// Update an agent session + pub async fn update( + &self, + agent_session: &str, + body: &PatchApiV1AgentSessionsAgentSessionInput, + ) -> Result { + let mut path = "/api/v1/agent_sessions/{agent_session}".to_owned(); + path = path.replace("{agent_session}", &crate::encode_path(agent_session)); + let request = self.client.request(Method::PATCH, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::update]. + #[cfg(feature = "blocking")] + pub fn update_blocking( + &self, + agent_session: &str, + body: &PatchApiV1AgentSessionsAgentSessionInput, + ) -> Result { + crate::blocking::block_on(self.update(agent_session, body)) + } + /// Cancel an agent session + pub async fn cancel(&self, agent_session: &str) -> Result { + let mut path = "/api/v1/agent_sessions/{agent_session}/cancel".to_owned(); + path = path.replace("{agent_session}", &crate::encode_path(agent_session)); + let request = self.client.request(Method::POST, &path); + request.send().await + } + /// Blocking variant of [Self::cancel]. + #[cfg(feature = "blocking")] + pub fn cancel_blocking(&self, agent_session: &str) -> Result { + crate::blocking::block_on(self.cancel(agent_session)) + } + /// Send a message to an agent session + pub async fn message( + &self, + agent_session: &str, + body: &PostApiV1AgentSessionsAgentSessionMessageInput, + ) -> Result { + let mut path = "/api/v1/agent_sessions/{agent_session}/message".to_owned(); + path = path.replace("{agent_session}", &crate::encode_path(agent_session)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::message]. + #[cfg(feature = "blocking")] + pub fn message_blocking( + &self, + agent_session: &str, + body: &PostApiV1AgentSessionsAgentSessionMessageInput, + ) -> Result { + crate::blocking::block_on(self.message(agent_session, body)) + } + /// Stream agent session status + pub async fn stream( + &self, + agent_session: &str, + ) -> Result> { + let mut path = "/api/v1/agent_sessions/{agent_session}/stream".to_owned(); + path = path.replace("{agent_session}", &crate::encode_path(agent_session)); + let request = self.client.request(Method::GET, &path); + request.stream().await + } +} + +/// agent_skills API resource. +#[derive(Clone)] +pub struct AgentSkillsResource { + client: Client, +} + +impl AgentSkillsResource { + /// List agent skills + pub async fn list(&self, params: Option<&GetApiV1AgentSkillsParams>) -> Result { + let path = "/api/v1/agent_skills".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1AgentSkillsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Enable a skill on an agent + pub async fn create(&self, body: &PostApiV1AgentSkillsInput) -> Result { + let path = "/api/v1/agent_skills".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1AgentSkillsInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Remove a skill from an agent + pub async fn delete(&self, agent_skill: &str) -> Result<()> { + let mut path = "/api/v1/agent_skills/{agent_skill}".to_owned(); + path = path.replace("{agent_skill}", &crate::encode_path(agent_skill)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, agent_skill: &str) -> Result<()> { + crate::blocking::block_on(self.delete(agent_skill)) + } + /// Retrieve an agent skill + pub async fn get(&self, agent_skill: &str) -> Result { + let mut path = "/api/v1/agent_skills/{agent_skill}".to_owned(); + path = path.replace("{agent_skill}", &crate::encode_path(agent_skill)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, agent_skill: &str) -> Result { + crate::blocking::block_on(self.get(agent_skill)) + } + /// Update an agent skill + pub async fn update( + &self, + agent_skill: &str, + body: &PatchApiV1AgentSkillsAgentSkillInput, + ) -> Result { + let mut path = "/api/v1/agent_skills/{agent_skill}".to_owned(); + path = path.replace("{agent_skill}", &crate::encode_path(agent_skill)); + let request = self.client.request(Method::PATCH, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::update]. + #[cfg(feature = "blocking")] + pub fn update_blocking( + &self, + agent_skill: &str, + body: &PatchApiV1AgentSkillsAgentSkillInput, + ) -> Result { + crate::blocking::block_on(self.update(agent_skill, body)) + } + /// Activate an agent skill + pub async fn activate(&self, agent_skill: &str) -> Result { + let mut path = "/api/v1/agent_skills/{agent_skill}/activate".to_owned(); + path = path.replace("{agent_skill}", &crate::encode_path(agent_skill)); + let request = self.client.request(Method::POST, &path); + request.send().await + } + /// Blocking variant of [Self::activate]. + #[cfg(feature = "blocking")] + pub fn activate_blocking(&self, agent_skill: &str) -> Result { + crate::blocking::block_on(self.activate(agent_skill)) + } + /// Deactivate an agent skill + pub async fn deactivate(&self, agent_skill: &str) -> Result { + let mut path = "/api/v1/agent_skills/{agent_skill}/deactivate".to_owned(); + path = path.replace("{agent_skill}", &crate::encode_path(agent_skill)); + let request = self.client.request(Method::POST, &path); + request.send().await + } + /// Blocking variant of [Self::deactivate]. + #[cfg(feature = "blocking")] + pub fn deactivate_blocking(&self, agent_skill: &str) -> Result { + crate::blocking::block_on(self.deactivate(agent_skill)) + } +} + +/// agent_tools API resource. +#[derive(Clone)] +pub struct AgentToolsResource { + client: Client, +} + +impl AgentToolsResource { + /// List agent tools + pub async fn list( + &self, + params: Option<&GetApiV1AgentToolsParams>, + ) -> Result { + let path = "/api/v1/agent_tools".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1AgentToolsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// List built-in tool categories + pub async fn catalog(&self) -> Result> { + let path = "/api/v1/agent_tools/catalog".to_owned(); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::catalog]. + #[cfg(feature = "blocking")] + pub fn catalog_blocking(&self) -> Result> { + crate::blocking::block_on(self.catalog()) + } + /// Delete an agent tool + pub async fn delete(&self, tool: &str) -> Result<()> { + let mut path = "/api/v1/agent_tools/{tool}".to_owned(); + path = path.replace("{tool}", &crate::encode_path(tool)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, tool: &str) -> Result<()> { + crate::blocking::block_on(self.delete(tool)) + } + /// Retrieve an agent tool + pub async fn get(&self, tool: &str) -> Result { + let mut path = "/api/v1/agent_tools/{tool}".to_owned(); + path = path.replace("{tool}", &crate::encode_path(tool)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, tool: &str) -> Result { + crate::blocking::block_on(self.get(tool)) + } + /// Update an agent tool + pub async fn update( + &self, + tool: &str, + body: &PatchApiV1AgentToolsToolInput, + ) -> Result { + let mut path = "/api/v1/agent_tools/{tool}".to_owned(); + path = path.replace("{tool}", &crate::encode_path(tool)); + let request = self.client.request(Method::PATCH, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::update]. + #[cfg(feature = "blocking")] + pub fn update_blocking( + &self, + tool: &str, + body: &PatchApiV1AgentToolsToolInput, + ) -> Result { + crate::blocking::block_on(self.update(tool, body)) + } + /// Activate an agent tool + pub async fn activate(&self, tool: &str) -> Result { + let mut path = "/api/v1/agent_tools/{tool}/activate".to_owned(); + path = path.replace("{tool}", &crate::encode_path(tool)); + let request = self.client.request(Method::POST, &path); + request.send().await + } + /// Blocking variant of [Self::activate]. + #[cfg(feature = "blocking")] + pub fn activate_blocking(&self, tool: &str) -> Result { + crate::blocking::block_on(self.activate(tool)) + } + /// Deactivate an agent tool + pub async fn deactivate(&self, tool: &str) -> Result { + let mut path = "/api/v1/agent_tools/{tool}/deactivate".to_owned(); + path = path.replace("{tool}", &crate::encode_path(tool)); + let request = self.client.request(Method::POST, &path); + request.send().await + } + /// Blocking variant of [Self::deactivate]. + #[cfg(feature = "blocking")] + pub fn deactivate_blocking(&self, tool: &str) -> Result { + crate::blocking::block_on(self.deactivate(tool)) + } +} + +/// agents API resource. +#[derive(Clone)] +pub struct AgentsResource { + client: Client, +} + +impl AgentsResource { + /// Access the nested agent_computers resource. + pub fn agent_computers(&self, agent: &str) -> AgentsAgentComputersResource { + AgentsAgentComputersResource { + client: self.client.clone(), + agent: agent.to_owned(), + } + } + /// Access the nested agent_env_vars resource. + pub fn agent_env_vars(&self, agent: &str) -> AgentsAgentEnvVarsResource { + AgentsAgentEnvVarsResource { + client: self.client.clone(), + agent: agent.to_owned(), + } + } + /// Access the nested agent_installations resource. + pub fn agent_installations(&self, agent: &str) -> AgentsAgentInstallationsResource { + AgentsAgentInstallationsResource { + client: self.client.clone(), + agent: agent.to_owned(), + } + } + /// Access the nested agent_tools resource. + pub fn agent_tools(&self, agent: &str) -> AgentsAgentToolsResource { + AgentsAgentToolsResource { + client: self.client.clone(), + agent: agent.to_owned(), + } + } + /// Access the nested agent_working_memory resource. + pub fn agent_working_memory(&self, agent: &str) -> AgentsAgentWorkingMemoryResource { + AgentsAgentWorkingMemoryResource { + client: self.client.clone(), + agent: agent.to_owned(), + } + } + /// Access the nested schedules resource. + pub fn schedules(&self, agent: &str) -> AgentsSchedulesResource { + AgentsSchedulesResource { + client: self.client.clone(), + agent: agent.to_owned(), + } + } + /// Access the nested work_items resource. + pub fn work_items(&self, agent: &str) -> AgentsWorkItemsResource { + AgentsWorkItemsResource { + client: self.client.clone(), + agent: agent.to_owned(), + } + } + /// List agents + pub async fn list(&self, params: Option<&GetApiV1AgentsParams>) -> Result { + let path = "/api/v1/agents".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1AgentsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create an agent + pub async fn create(&self, body: &PostApiV1AgentsInput) -> Result { + let path = "/api/v1/agents".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1AgentsInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Delete an agent + pub async fn delete(&self, agent: &str) -> Result<()> { + let mut path = "/api/v1/agents/{agent}".to_owned(); + path = path.replace("{agent}", &crate::encode_path(agent)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, agent: &str) -> Result<()> { + crate::blocking::block_on(self.delete(agent)) + } + /// Retrieve an agent + pub async fn get(&self, agent: &str) -> Result { + let mut path = "/api/v1/agents/{agent}".to_owned(); + path = path.replace("{agent}", &crate::encode_path(agent)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, agent: &str) -> Result { + crate::blocking::block_on(self.get(agent)) + } + /// Update an agent + pub async fn update(&self, agent: &str, body: &PatchApiV1AgentsAgentInput) -> Result { + let mut path = "/api/v1/agents/{agent}".to_owned(); + path = path.replace("{agent}", &crate::encode_path(agent)); + let request = self.client.request(Method::PATCH, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::update]. + #[cfg(feature = "blocking")] + pub fn update_blocking(&self, agent: &str, body: &PatchApiV1AgentsAgentInput) -> Result { + crate::blocking::block_on(self.update(agent, body)) + } + /// List health actions for an agent + pub async fn agent_health_actions( + &self, + agent: &str, + params: Option<&GetApiV1AgentsAgentAgentHealthActionsParams>, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/agent_health_actions".to_owned(); + path = path.replace("{agent}", &crate::encode_path(agent)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::agent_health_actions]. + #[cfg(feature = "blocking")] + pub fn agent_health_actions_blocking( + &self, + agent: &str, + params: Option<&GetApiV1AgentsAgentAgentHealthActionsParams>, + ) -> Result { + crate::blocking::block_on(self.agent_health_actions(agent, params)) + } + /// Create a routine + pub async fn agent_routines( + &self, + agent: &str, + body: &PostApiV1AgentsAgentAgentRoutinesInput, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/agent_routines".to_owned(); + path = path.replace("{agent}", &crate::encode_path(agent)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::agent_routines]. + #[cfg(feature = "blocking")] + pub fn agent_routines_blocking( + &self, + agent: &str, + body: &PostApiV1AgentsAgentAgentRoutinesInput, + ) -> Result { + crate::blocking::block_on(self.agent_routines(agent, body)) + } + /// Export an agent as an AgentTemplate + pub async fn export( + &self, + agent: &str, + params: Option<&GetApiV1AgentsAgentExportParams>, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/export".to_owned(); + path = path.replace("{agent}", &crate::encode_path(agent)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::export]. + #[cfg(feature = "blocking")] + pub fn export_blocking( + &self, + agent: &str, + params: Option<&GetApiV1AgentsAgentExportParams>, + ) -> Result { + crate::blocking::block_on(self.export(agent, params)) + } + /// Retrieve an agent's health profile + pub async fn health(&self, agent: &str) -> Result { + let mut path = "/api/v1/agents/{agent}/health".to_owned(); + path = path.replace("{agent}", &crate::encode_path(agent)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::health]. + #[cfg(feature = "blocking")] + pub fn health_blocking(&self, agent: &str) -> Result { + crate::blocking::block_on(self.health(agent)) + } + /// Search an agent's knowledge base + pub async fn search( + &self, + agent: &str, + body: &PostApiV1AgentsAgentSearchInput, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/search".to_owned(); + path = path.replace("{agent}", &crate::encode_path(agent)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::search]. + #[cfg(feature = "blocking")] + pub fn search_blocking( + &self, + agent: &str, + body: &PostApiV1AgentsAgentSearchInput, + ) -> Result { + crate::blocking::block_on(self.search(agent, body)) + } + /// Create a thread for an agent + pub async fn threads( + &self, + agent: &str, + body: &PostApiV1AgentsAgentThreadsInput, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/threads".to_owned(); + path = path.replace("{agent}", &crate::encode_path(agent)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::threads]. + #[cfg(feature = "blocking")] + pub fn threads_blocking( + &self, + agent: &str, + body: &PostApiV1AgentsAgentThreadsInput, + ) -> Result { + crate::blocking::block_on(self.threads(agent, body)) + } + /// Upgrade an agent from an AgentTemplate + pub async fn upgrade( + &self, + agent: &str, + body: &PostApiV1AgentsAgentUpgradeInput, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/upgrade".to_owned(); + path = path.replace("{agent}", &crate::encode_path(agent)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::upgrade]. + #[cfg(feature = "blocking")] + pub fn upgrade_blocking( + &self, + agent: &str, + body: &PostApiV1AgentsAgentUpgradeInput, + ) -> Result { + crate::blocking::block_on(self.upgrade(agent, body)) + } +} + +/// agent_computers API resource. +#[derive(Clone)] +pub struct AgentsAgentComputersResource { + client: Client, + /// Bound agent scope. + agent: String, +} + +impl AgentsAgentComputersResource { + /// List computers + pub async fn list(&self) -> Result { + let mut path = "/api/v1/agents/{agent}/agent_computers".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking(&self) -> Result { + crate::blocking::block_on(self.list()) + } + /// Provision a computer for an agent + pub async fn create( + &self, + body: &PostApiV1AgentsAgentAgentComputersInput, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/agent_computers".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking( + &self, + body: &PostApiV1AgentsAgentAgentComputersInput, + ) -> Result { + crate::blocking::block_on(self.create(body)) + } +} + +/// agent_env_vars API resource. +#[derive(Clone)] +pub struct AgentsAgentEnvVarsResource { + client: Client, + /// Bound agent scope. + agent: String, +} + +impl AgentsAgentEnvVarsResource { + /// List an agent's environment variables + pub async fn list(&self) -> Result { + let mut path = "/api/v1/agents/{agent}/agent_env_vars".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking(&self) -> Result { + crate::blocking::block_on(self.list()) + } + /// Create an agent environment variable + pub async fn create( + &self, + body: &PostApiV1AgentsAgentAgentEnvVarsInput, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/agent_env_vars".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking( + &self, + body: &PostApiV1AgentsAgentAgentEnvVarsInput, + ) -> Result { + crate::blocking::block_on(self.create(body)) + } +} + +/// agent_installations API resource. +#[derive(Clone)] +pub struct AgentsAgentInstallationsResource { + client: Client, + /// Bound agent scope. + agent: String, +} + +impl AgentsAgentInstallationsResource { + /// List installations for an agent + pub async fn list(&self) -> Result { + let mut path = "/api/v1/agents/{agent}/agent_installations".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking(&self) -> Result { + crate::blocking::block_on(self.list()) + } + /// Create an installation + pub async fn create( + &self, + body: &PostApiV1AgentsAgentAgentInstallationsInput, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/agent_installations".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking( + &self, + body: &PostApiV1AgentsAgentAgentInstallationsInput, + ) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// List available installation kinds + pub async fn kinds(&self) -> Result { + let mut path = "/api/v1/agents/{agent}/agent_installations/kinds".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::kinds]. + #[cfg(feature = "blocking")] + pub fn kinds_blocking(&self) -> Result { + crate::blocking::block_on(self.kinds()) + } +} + +/// agent_tools API resource. +#[derive(Clone)] +pub struct AgentsAgentToolsResource { + client: Client, + /// Bound agent scope. + agent: String, +} + +impl AgentsAgentToolsResource { + /// List agent tools + pub async fn list( + &self, + params: Option<&GetApiV1AgentsAgentAgentToolsParams>, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/agent_tools".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1AgentsAgentAgentToolsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create an agent tool + pub async fn create(&self, body: &PostApiV1AgentsAgentAgentToolsInput) -> Result { + let mut path = "/api/v1/agents/{agent}/agent_tools".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1AgentsAgentAgentToolsInput) -> Result { + crate::blocking::block_on(self.create(body)) + } +} + +/// agent_working_memory API resource. +#[derive(Clone)] +pub struct AgentsAgentWorkingMemoryResource { + client: Client, + /// Bound agent scope. + agent: String, +} + +impl AgentsAgentWorkingMemoryResource { + /// List working memory entries for an agent + pub async fn list( + &self, + params: Option<&GetApiV1AgentsAgentAgentWorkingMemoryParams>, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/agent_working_memory".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1AgentsAgentAgentWorkingMemoryParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Delete a working memory entry + pub async fn delete(&self, entry: &str) -> Result<()> { + let mut path = "/api/v1/agents/{agent}/agent_working_memory/{entry}".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + path = path.replace("{entry}", &crate::encode_path(entry)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, entry: &str) -> Result<()> { + crate::blocking::block_on(self.delete(entry)) + } + /// Update a working memory entry + pub async fn update( + &self, + entry: &str, + body: &PatchApiV1AgentsAgentAgentWorkingMemoryEntryInput, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/agent_working_memory/{entry}".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + path = path.replace("{entry}", &crate::encode_path(entry)); + let request = self.client.request(Method::PATCH, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::update]. + #[cfg(feature = "blocking")] + pub fn update_blocking( + &self, + entry: &str, + body: &PatchApiV1AgentsAgentAgentWorkingMemoryEntryInput, + ) -> Result { + crate::blocking::block_on(self.update(entry, body)) + } +} + +/// schedules API resource. +#[derive(Clone)] +pub struct AgentsSchedulesResource { + client: Client, + /// Bound agent scope. + agent: String, +} + +impl AgentsSchedulesResource { + /// List schedules for an agent + pub async fn list( + &self, + params: Option<&GetApiV1AgentsAgentSchedulesParams>, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/schedules".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1AgentsAgentSchedulesParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Retrieve a schedule + pub async fn get(&self, schedule: &str) -> Result { + let mut path = "/api/v1/agents/{agent}/schedules/{schedule}".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + path = path.replace("{schedule}", &crate::encode_path(schedule)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, schedule: &str) -> Result { + crate::blocking::block_on(self.get(schedule)) + } +} + +/// work_items API resource. +#[derive(Clone)] +pub struct AgentsWorkItemsResource { + client: Client, + /// Bound agent scope. + agent: String, +} + +impl AgentsWorkItemsResource { + /// List active workflow work available to the viewer + pub async fn list( + &self, + params: Option<&GetApiV1AgentsAgentWorkItemsParams>, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/work_items".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1AgentsAgentWorkItemsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Claim or resume workflow work for an agent + pub async fn claim( + &self, + body: &PostApiV1AgentsAgentWorkItemsClaimInput, + ) -> Result { + let mut path = "/api/v1/agents/{agent}/work_items/claim".to_owned(); + path = path.replace("{agent}", &crate::encode_path(self.agent.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::claim]. + #[cfg(feature = "blocking")] + pub fn claim_blocking( + &self, + body: &PostApiV1AgentsAgentWorkItemsClaimInput, + ) -> Result { + crate::blocking::block_on(self.claim(body)) + } +} + +/// artifacts API resource. +#[derive(Clone)] +pub struct ArtifactsResource { + client: Client, +} + +impl ArtifactsResource { + /// Delete an artifact + pub async fn delete(&self, artifact: &str) -> Result<()> { + let mut path = "/api/v1/artifacts/{artifact}".to_owned(); + path = path.replace("{artifact}", &crate::encode_path(artifact)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, artifact: &str) -> Result<()> { + crate::blocking::block_on(self.delete(artifact)) + } + /// Retrieve an artifact + pub async fn get(&self, artifact: &str) -> Result { + let mut path = "/api/v1/artifacts/{artifact}".to_owned(); + path = path.replace("{artifact}", &crate::encode_path(artifact)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, artifact: &str) -> Result { + crate::blocking::block_on(self.get(artifact)) + } + /// Update an artifact + pub async fn replace( + &self, + artifact: &str, + body: &PutApiV1ArtifactsArtifactInput, + ) -> Result { + let mut path = "/api/v1/artifacts/{artifact}".to_owned(); + path = path.replace("{artifact}", &crate::encode_path(artifact)); + let request = self.client.request(Method::PUT, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::replace]. + #[cfg(feature = "blocking")] + pub fn replace_blocking( + &self, + artifact: &str, + body: &PutApiV1ArtifactsArtifactInput, + ) -> Result { + crate::blocking::block_on(self.replace(artifact, body)) + } + /// Archive an artifact + pub async fn archive(&self, artifact: &str) -> Result<()> { + let mut path = "/api/v1/artifacts/{artifact}/archive".to_owned(); + path = path.replace("{artifact}", &crate::encode_path(artifact)); + let request = self.client.request(Method::POST, &path); + request.send_empty().await + } + /// Blocking variant of [Self::archive]. + #[cfg(feature = "blocking")] + pub fn archive_blocking(&self, artifact: &str) -> Result<()> { + crate::blocking::block_on(self.archive(artifact)) + } + /// Retrieve raw artifact file content + pub async fn content( + &self, + artifact: &str, + params: Option<&GetApiV1ArtifactsArtifactContentParams>, + ) -> Result { + let mut path = "/api/v1/artifacts/{artifact}/content".to_owned(); + path = path.replace("{artifact}", &crate::encode_path(artifact)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send_raw().await + } + /// Blocking variant of [Self::content]. + #[cfg(feature = "blocking")] + pub fn content_blocking( + &self, + artifact: &str, + params: Option<&GetApiV1ArtifactsArtifactContentParams>, + ) -> Result { + crate::blocking::block_on(self.content(artifact, params)) + } +} + +/// automation_runs API resource. +#[derive(Clone)] +pub struct AutomationRunsResource { + client: Client, +} + +impl AutomationRunsResource { + /// Retrieve an automation run + pub async fn get(&self, automation_run: &str) -> Result { + let mut path = "/api/v1/automation_runs/{automation_run}".to_owned(); + path = path.replace("{automation_run}", &crate::encode_path(automation_run)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, automation_run: &str) -> Result { + crate::blocking::block_on(self.get(automation_run)) + } + /// List an automation run journal + pub async fn journal( + &self, + automation_run: &str, + params: Option<&GetApiV1AutomationRunsAutomationRunJournalParams>, + ) -> Result { + let mut path = "/api/v1/automation_runs/{automation_run}/journal".to_owned(); + path = path.replace("{automation_run}", &crate::encode_path(automation_run)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::journal]. + #[cfg(feature = "blocking")] + pub fn journal_blocking( + &self, + automation_run: &str, + params: Option<&GetApiV1AutomationRunsAutomationRunJournalParams>, + ) -> Result { + crate::blocking::block_on(self.journal(automation_run, params)) + } + /// Stream automation run status + pub async fn stream( + &self, + automation_run: &str, + ) -> Result> { + let mut path = "/api/v1/automation_runs/{automation_run}/stream".to_owned(); + path = path.replace("{automation_run}", &crate::encode_path(automation_run)); + let request = self.client.request(Method::GET, &path); + request.stream().await + } +} + +/// automations API resource. +#[derive(Clone)] +pub struct AutomationsResource { + client: Client, +} + +impl AutomationsResource { + /// Invoke an automation + pub async fn invoke( + &self, + automation: &str, + body: &PostApiV1AutomationsAutomationInvokeInput, + ) -> Result { + let mut path = "/api/v1/automations/{automation}/invoke".to_owned(); + path = path.replace("{automation}", &crate::encode_path(automation)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::invoke]. + #[cfg(feature = "blocking")] + pub fn invoke_blocking( + &self, + automation: &str, + body: &PostApiV1AutomationsAutomationInvokeInput, + ) -> Result { + crate::blocking::block_on(self.invoke(automation, body)) + } +} + +/// bug_reports API resource. +#[derive(Clone)] +pub struct BugReportsResource { + client: Client, +} + +impl BugReportsResource { + /// Submit a bug report + pub async fn create(&self, body: &PostApiV1BugReportsInput) -> Result { + let path = "/api/v1/bug_reports".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1BugReportsInput) -> Result { + crate::blocking::block_on(self.create(body)) + } +} + +/// config API resource. +#[derive(Clone)] +pub struct ConfigResource { + client: Client, +} + +impl ConfigResource { + /// Access the nested kinds resource. + pub fn kinds(&self) -> ConfigKindsResource { + ConfigKindsResource { + client: self.client.clone(), + } + } + /// Access the nested system resource. + pub fn system(&self) -> ConfigSystemResource { + ConfigSystemResource { + client: self.client.clone(), + } + } + /// List configs + pub async fn list( + &self, + params: Option<&GetApiV1ConfigParams>, + ) -> Result { + let path = "/api/v1/config".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1ConfigParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create a config + pub async fn create(&self, body: &PostApiV1ConfigInput) -> Result { + let path = "/api/v1/config".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1ConfigInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Encrypt a secret for use in a config + pub async fn encrypt_secret( + &self, + body: &PostApiV1ConfigEncryptSecretInput, + ) -> Result { + let path = "/api/v1/config/encrypt_secret".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::encrypt_secret]. + #[cfg(feature = "blocking")] + pub fn encrypt_secret_blocking( + &self, + body: &PostApiV1ConfigEncryptSecretInput, + ) -> Result { + crate::blocking::block_on(self.encrypt_secret(body)) + } + /// List config facets + pub async fn facets( + &self, + params: Option<&GetApiV1ConfigFacetsParams>, + ) -> Result { + let path = "/api/v1/config/facets".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::facets]. + #[cfg(feature = "blocking")] + pub fn facets_blocking( + &self, + params: Option<&GetApiV1ConfigFacetsParams>, + ) -> Result { + crate::blocking::block_on(self.facets(params)) + } + /// Validate config content + pub async fn validate(&self, body: &PostApiV1ConfigValidateInput) -> Result { + let path = "/api/v1/config/validate".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::validate]. + #[cfg(feature = "blocking")] + pub fn validate_blocking( + &self, + body: &PostApiV1ConfigValidateInput, + ) -> Result { + crate::blocking::block_on(self.validate(body)) + } + /// Delete a config + pub async fn delete(&self, config: &str) -> Result<()> { + let mut path = "/api/v1/config/{config}".to_owned(); + path = path.replace("{config}", &crate::encode_path(config)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, config: &str) -> Result<()> { + crate::blocking::block_on(self.delete(config)) + } + /// Retrieve a config + pub async fn get( + &self, + config: &str, + params: Option<&GetApiV1ConfigConfigParams>, + ) -> Result { + let mut path = "/api/v1/config/{config}".to_owned(); + path = path.replace("{config}", &crate::encode_path(config)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking( + &self, + config: &str, + params: Option<&GetApiV1ConfigConfigParams>, + ) -> Result { + crate::blocking::block_on(self.get(config, params)) + } + /// Update a config + pub async fn update(&self, config: &str, body: &PatchApiV1ConfigConfigInput) -> Result { + let mut path = "/api/v1/config/{config}".to_owned(); + path = path.replace("{config}", &crate::encode_path(config)); + let request = self.client.request(Method::PATCH, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::update]. + #[cfg(feature = "blocking")] + pub fn update_blocking( + &self, + config: &str, + body: &PatchApiV1ConfigConfigInput, + ) -> Result { + crate::blocking::block_on(self.update(config, body)) + } + /// Archive a config + pub async fn archive( + &self, + config: &str, + body: &PostApiV1ConfigConfigArchiveInput, + ) -> Result { + let mut path = "/api/v1/config/{config}/archive".to_owned(); + path = path.replace("{config}", &crate::encode_path(config)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::archive]. + #[cfg(feature = "blocking")] + pub fn archive_blocking( + &self, + config: &str, + body: &PostApiV1ConfigConfigArchiveInput, + ) -> Result { + crate::blocking::block_on(self.archive(config, body)) + } + /// Transfer ownership of a config + pub async fn change_owner( + &self, + config: &str, + body: &PostApiV1ConfigConfigChangeOwnerInput, + ) -> Result { + let mut path = "/api/v1/config/{config}/change_owner".to_owned(); + path = path.replace("{config}", &crate::encode_path(config)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::change_owner]. + #[cfg(feature = "blocking")] + pub fn change_owner_blocking( + &self, + config: &str, + body: &PostApiV1ConfigConfigChangeOwnerInput, + ) -> Result { + crate::blocking::block_on(self.change_owner(config, body)) + } + /// Retrieve a config's raw content + pub async fn content( + &self, + config: &str, + params: Option<&GetApiV1ConfigConfigContentParams>, + ) -> Result { + let mut path = "/api/v1/config/{config}/content".to_owned(); + path = path.replace("{config}", &crate::encode_path(config)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send_raw().await + } + /// Blocking variant of [Self::content]. + #[cfg(feature = "blocking")] + pub fn content_blocking( + &self, + config: &str, + params: Option<&GetApiV1ConfigConfigContentParams>, + ) -> Result { + crate::blocking::block_on(self.content(config, params)) + } + /// Unarchive a config + pub async fn unarchive( + &self, + config: &str, + body: &PostApiV1ConfigConfigUnarchiveInput, + ) -> Result { + let mut path = "/api/v1/config/{config}/unarchive".to_owned(); + path = path.replace("{config}", &crate::encode_path(config)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::unarchive]. + #[cfg(feature = "blocking")] + pub fn unarchive_blocking( + &self, + config: &str, + body: &PostApiV1ConfigConfigUnarchiveInput, + ) -> Result { + crate::blocking::block_on(self.unarchive(config, body)) + } + /// List a config's version history + pub async fn versions( + &self, + config: &str, + params: Option<&GetApiV1ConfigConfigVersionsParams>, + ) -> Result { + let mut path = "/api/v1/config/{config}/versions".to_owned(); + path = path.replace("{config}", &crate::encode_path(config)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::versions]. + #[cfg(feature = "blocking")] + pub fn versions_blocking( + &self, + config: &str, + params: Option<&GetApiV1ConfigConfigVersionsParams>, + ) -> Result { + crate::blocking::block_on(self.versions(config, params)) + } +} + +/// kinds API resource. +#[derive(Clone)] +pub struct ConfigKindsResource { + client: Client, +} + +impl ConfigKindsResource { + /// List config kinds + pub async fn list( + &self, + params: Option<&GetApiV1ConfigKindsParams>, + ) -> Result { + let path = "/api/v1/config/kinds".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1ConfigKindsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Retrieve a config kind schema + pub async fn schema(&self, kind: &str) -> Result { + let mut path = "/api/v1/config/kinds/{kind}/schema".to_owned(); + path = path.replace("{kind}", &crate::encode_path(kind)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::schema]. + #[cfg(feature = "blocking")] + pub fn schema_blocking(&self, kind: &str) -> Result { + crate::blocking::block_on(self.schema(kind)) + } +} + +/// system API resource. +#[derive(Clone)] +pub struct ConfigSystemResource { + client: Client, +} + +impl ConfigSystemResource { + /// List system configs + pub async fn list( + &self, + params: Option<&GetApiV1ConfigSystemParams>, + ) -> Result { + let path = "/api/v1/config/system".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1ConfigSystemParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Retrieve system config facets + pub async fn facets(&self) -> Result { + let path = "/api/v1/config/system/facets".to_owned(); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::facets]. + #[cfg(feature = "blocking")] + pub fn facets_blocking(&self) -> Result { + crate::blocking::block_on(self.facets()) + } + /// Retrieve a system config + pub async fn get(&self, system: &str) -> Result { + let mut path = "/api/v1/config/system/{system}".to_owned(); + path = path.replace("{system}", &crate::encode_path(system)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, system: &str) -> Result { + crate::blocking::block_on(self.get(system)) + } + /// Clone a system config + pub async fn clone( + &self, + system: &str, + body: &PostApiV1ConfigSystemSystemCloneInput, + ) -> Result { + let mut path = "/api/v1/config/system/{system}/clone".to_owned(); + path = path.replace("{system}", &crate::encode_path(system)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::clone]. + #[cfg(feature = "blocking")] + pub fn clone_blocking( + &self, + system: &str, + body: &PostApiV1ConfigSystemSystemCloneInput, + ) -> Result { + crate::blocking::block_on(self.clone(system, body)) + } +} + +/// custom_objects API resource. +#[derive(Clone)] +pub struct CustomObjectsResource { + client: Client, +} + +impl CustomObjectsResource { + /// List custom objects + pub async fn list( + &self, + params: Option<&GetApiV1CustomObjectsParams>, + ) -> Result { + let path = "/api/v1/custom_objects".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1CustomObjectsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create a custom object + pub async fn create(&self, body: &PostApiV1CustomObjectsInput) -> Result { + let path = "/api/v1/custom_objects".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1CustomObjectsInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Delete a custom object + pub async fn delete(&self, object: &str) -> Result { + let mut path = "/api/v1/custom_objects/{object}".to_owned(); + path = path.replace("{object}", &crate::encode_path(object)); + let request = self.client.request(Method::DELETE, &path); + request.send().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, object: &str) -> Result { + crate::blocking::block_on(self.delete(object)) + } + /// Retrieve a custom object + pub async fn get( + &self, + object: &str, + params: Option<&GetApiV1CustomObjectsObjectParams>, + ) -> Result { + let mut path = "/api/v1/custom_objects/{object}".to_owned(); + path = path.replace("{object}", &crate::encode_path(object)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking( + &self, + object: &str, + params: Option<&GetApiV1CustomObjectsObjectParams>, + ) -> Result { + crate::blocking::block_on(self.get(object, params)) + } + /// Update a custom object + pub async fn replace( + &self, + object: &str, + body: &PutApiV1CustomObjectsObjectInput, + ) -> Result { + let mut path = "/api/v1/custom_objects/{object}".to_owned(); + path = path.replace("{object}", &crate::encode_path(object)); + let request = self.client.request(Method::PUT, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::replace]. + #[cfg(feature = "blocking")] + pub fn replace_blocking( + &self, + object: &str, + body: &PutApiV1CustomObjectsObjectInput, + ) -> Result { + crate::blocking::block_on(self.replace(object, body)) + } +} + +/// extractions API resource. +#[derive(Clone)] +pub struct ExtractionsResource { + client: Client, +} + +impl ExtractionsResource { + /// Start an extraction + pub async fn create(&self, body: &PostApiV1ExtractionsInput) -> Result { + let path = "/api/v1/extractions".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1ExtractionsInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Retrieve an extraction + pub async fn get(&self, extraction: &str) -> Result { + let mut path = "/api/v1/extractions/{extraction}".to_owned(); + path = path.replace("{extraction}", &crate::encode_path(extraction)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, extraction: &str) -> Result { + crate::blocking::block_on(self.get(extraction)) + } +} + +/// files API resource. +#[derive(Clone)] +pub struct FilesResource { + client: Client, +} + +impl FilesResource { + /// Upload a file + pub async fn create(&self, body: &PostApiV1FilesInput) -> Result { + let path = "/api/v1/files".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1FilesInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Update a file + pub async fn update(&self, file: &str, body: &PatchApiV1FilesFileInput) -> Result { + let mut path = "/api/v1/files/{file}".to_owned(); + path = path.replace("{file}", &crate::encode_path(file)); + let request = self.client.request(Method::PATCH, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::update]. + #[cfg(feature = "blocking")] + pub fn update_blocking( + &self, + file: &str, + body: &PatchApiV1FilesFileInput, + ) -> Result { + crate::blocking::block_on(self.update(file, body)) + } + /// Fetch an agent avatar image + pub async fn avatar( + &self, + file: &str, + params: &GetApiV1FilesFileAvatarParams, + ) -> Result { + let mut path = "/api/v1/files/{file}/avatar".to_owned(); + path = path.replace("{file}", &crate::encode_path(file)); + let request = self.client.request(Method::GET, &path); + let request = request.query(params)?; + request.send_raw().await + } + /// Blocking variant of [Self::avatar]. + #[cfg(feature = "blocking")] + pub fn avatar_blocking( + &self, + file: &str, + params: &GetApiV1FilesFileAvatarParams, + ) -> Result { + crate::blocking::block_on(self.avatar(file, params)) + } + /// Fetch an org logo image + pub async fn org_logo( + &self, + file: &str, + params: &GetApiV1FilesFileOrgLogoParams, + ) -> Result { + let mut path = "/api/v1/files/{file}/org_logo".to_owned(); + path = path.replace("{file}", &crate::encode_path(file)); + let request = self.client.request(Method::GET, &path); + let request = request.query(params)?; + request.send_raw().await + } + /// Blocking variant of [Self::org_logo]. + #[cfg(feature = "blocking")] + pub fn org_logo_blocking( + &self, + file: &str, + params: &GetApiV1FilesFileOrgLogoParams, + ) -> Result { + crate::blocking::block_on(self.org_logo(file, params)) + } + /// Fetch a publicly shared file + pub async fn share( + &self, + file: &str, + params: &GetApiV1FilesFileShareParams, + ) -> Result { + let mut path = "/api/v1/files/{file}/share".to_owned(); + path = path.replace("{file}", &crate::encode_path(file)); + let request = self.client.request(Method::GET, &path); + let request = request.query(params)?; + request.send_raw().await + } + /// Blocking variant of [Self::share]. + #[cfg(feature = "blocking")] + pub fn share_blocking( + &self, + file: &str, + params: &GetApiV1FilesFileShareParams, + ) -> Result { + crate::blocking::block_on(self.share(file, params)) + } +} + +/// installation_sources API resource. +#[derive(Clone)] +pub struct InstallationSourcesResource { + client: Client, +} + +impl InstallationSourcesResource { + /// Remove a source from an installation + pub async fn delete(&self, source: &str) -> Result<()> { + let mut path = "/api/v1/installation_sources/{source}".to_owned(); + path = path.replace("{source}", &crate::encode_path(source)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, source: &str) -> Result<()> { + crate::blocking::block_on(self.delete(source)) + } +} + +/// invites API resource. +#[derive(Clone)] +pub struct InvitesResource { + client: Client, +} + +impl InvitesResource { + /// Accept an invite + pub async fn accept(&self, body: &PostApiV1InvitesAcceptInput) -> Result { + let path = "/api/v1/invites/accept".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::accept]. + #[cfg(feature = "blocking")] + pub fn accept_blocking(&self, body: &PostApiV1InvitesAcceptInput) -> Result { + crate::blocking::block_on(self.accept(body)) + } +} + +/// knowledge_documents API resource. +#[derive(Clone)] +pub struct KnowledgeDocumentsResource { + client: Client, +} + +impl KnowledgeDocumentsResource { + /// List context documents + pub async fn list( + &self, + params: Option<&GetApiV1KnowledgeDocumentsParams>, + ) -> Result { + let path = "/api/v1/knowledge_documents".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1KnowledgeDocumentsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Delete a context document + pub async fn delete(&self, document: &str) -> Result<()> { + let mut path = "/api/v1/knowledge_documents/{document}".to_owned(); + path = path.replace("{document}", &crate::encode_path(document)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, document: &str) -> Result<()> { + crate::blocking::block_on(self.delete(document)) + } + /// Retrieve a context document + pub async fn get(&self, document: &str) -> Result { + let mut path = "/api/v1/knowledge_documents/{document}".to_owned(); + path = path.replace("{document}", &crate::encode_path(document)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, document: &str) -> Result { + crate::blocking::block_on(self.get(document)) + } + /// Update a context document + pub async fn update( + &self, + document: &str, + body: &PatchApiV1KnowledgeDocumentsDocumentInput, + ) -> Result { + let mut path = "/api/v1/knowledge_documents/{document}".to_owned(); + path = path.replace("{document}", &crate::encode_path(document)); + let request = self.client.request(Method::PATCH, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::update]. + #[cfg(feature = "blocking")] + pub fn update_blocking( + &self, + document: &str, + body: &PatchApiV1KnowledgeDocumentsDocumentInput, + ) -> Result { + crate::blocking::block_on(self.update(document, body)) + } + /// Retrieve a context document's content + pub async fn content( + &self, + document: &str, + params: Option<&GetApiV1KnowledgeDocumentsDocumentContentParams>, + ) -> Result { + let mut path = "/api/v1/knowledge_documents/{document}/content".to_owned(); + path = path.replace("{document}", &crate::encode_path(document)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::content]. + #[cfg(feature = "blocking")] + pub fn content_blocking( + &self, + document: &str, + params: Option<&GetApiV1KnowledgeDocumentsDocumentContentParams>, + ) -> Result { + crate::blocking::block_on(self.content(document, params)) + } +} + +/// knowledge_ingestions API resource. +#[derive(Clone)] +pub struct KnowledgeIngestionsResource { + client: Client, +} + +impl KnowledgeIngestionsResource { + /// Retrieve a knowledge ingestion + pub async fn get(&self, ingestion: &str) -> Result { + let mut path = "/api/v1/knowledge_ingestions/{ingestion}".to_owned(); + path = path.replace("{ingestion}", &crate::encode_path(ingestion)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, ingestion: &str) -> Result { + crate::blocking::block_on(self.get(ingestion)) + } +} + +/// knowledge_sources API resource. +#[derive(Clone)] +pub struct KnowledgeSourcesResource { + client: Client, +} + +impl KnowledgeSourcesResource { + /// Access the nested kinds resource. + pub fn kinds(&self) -> KnowledgeSourcesKindsResource { + KnowledgeSourcesKindsResource { + client: self.client.clone(), + } + } + /// List knowledge sources + pub async fn list( + &self, + params: Option<&GetApiV1KnowledgeSourcesParams>, + ) -> Result { + let path = "/api/v1/knowledge_sources".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1KnowledgeSourcesParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create a knowledge source + pub async fn create(&self, body: &PostApiV1KnowledgeSourcesInput) -> Result { + let path = "/api/v1/knowledge_sources".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking( + &self, + body: &PostApiV1KnowledgeSourcesInput, + ) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Delete a knowledge source + pub async fn delete(&self, source: &str) -> Result<()> { + let mut path = "/api/v1/knowledge_sources/{source}".to_owned(); + path = path.replace("{source}", &crate::encode_path(source)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, source: &str) -> Result<()> { + crate::blocking::block_on(self.delete(source)) + } + /// Retrieve a knowledge source + pub async fn get(&self, source: &str) -> Result { + let mut path = "/api/v1/knowledge_sources/{source}".to_owned(); + path = path.replace("{source}", &crate::encode_path(source)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, source: &str) -> Result { + crate::blocking::block_on(self.get(source)) + } + /// Update a knowledge source + pub async fn update( + &self, + source: &str, + body: &PatchApiV1KnowledgeSourcesSourceInput, + ) -> Result { + let mut path = "/api/v1/knowledge_sources/{source}".to_owned(); + path = path.replace("{source}", &crate::encode_path(source)); + let request = self.client.request(Method::PATCH, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::update]. + #[cfg(feature = "blocking")] + pub fn update_blocking( + &self, + source: &str, + body: &PatchApiV1KnowledgeSourcesSourceInput, + ) -> Result { + crate::blocking::block_on(self.update(source, body)) + } + /// Trigger ingestion on a knowledge source + pub async fn ingest( + &self, + source: &str, + body: &PostApiV1KnowledgeSourcesSourceIngestInput, + ) -> Result { + let mut path = "/api/v1/knowledge_sources/{source}/ingest".to_owned(); + path = path.replace("{source}", &crate::encode_path(source)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::ingest]. + #[cfg(feature = "blocking")] + pub fn ingest_blocking( + &self, + source: &str, + body: &PostApiV1KnowledgeSourcesSourceIngestInput, + ) -> Result { + crate::blocking::block_on(self.ingest(source, body)) + } +} + +/// kinds API resource. +#[derive(Clone)] +pub struct KnowledgeSourcesKindsResource { + client: Client, +} + +impl KnowledgeSourcesKindsResource { + /// List creatable knowledge source kinds + pub async fn list(&self) -> Result { + let path = "/api/v1/knowledge_sources/kinds".to_owned(); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking(&self) -> Result { + crate::blocking::block_on(self.list()) + } +} + +/// kv API resource. +#[derive(Clone)] +pub struct KvResource { + client: Client, +} + +impl KvResource { + /// List key-value storage entries + pub async fn list( + &self, + params: Option<&GetApiV1KvParams>, + ) -> Result { + let path = "/api/v1/kv".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1KvParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create a key-value storage entry + pub async fn create(&self, body: &PostApiV1KvInput) -> Result { + let path = "/api/v1/kv".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1KvInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Delete a key-value storage entry + pub async fn delete(&self, key: &str) -> Result<()> { + let mut path = "/api/v1/kv/{key}".to_owned(); + path = path.replace("{key}", &crate::encode_path(key)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, key: &str) -> Result<()> { + crate::blocking::block_on(self.delete(key)) + } + /// Retrieve a key-value storage entry + pub async fn get( + &self, + key: &str, + params: Option<&GetApiV1KvKeyParams>, + ) -> Result { + let mut path = "/api/v1/kv/{key}".to_owned(); + path = path.replace("{key}", &crate::encode_path(key)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking( + &self, + key: &str, + params: Option<&GetApiV1KvKeyParams>, + ) -> Result { + crate::blocking::block_on(self.get(key, params)) + } + /// Create or update a key-value storage entry + pub async fn upsert( + &self, + key: &str, + body: &PutApiV1KvKeyInput, + ) -> Result { + let mut path = "/api/v1/kv/{key}".to_owned(); + path = path.replace("{key}", &crate::encode_path(key)); + let request = self.client.request(Method::PUT, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::upsert]. + #[cfg(feature = "blocking")] + pub fn upsert_blocking( + &self, + key: &str, + body: &PutApiV1KvKeyInput, + ) -> Result { + crate::blocking::block_on(self.upsert(key, body)) + } +} + +/// notification_preferences API resource. +#[derive(Clone)] +pub struct NotificationPreferencesResource { + client: Client, +} + +impl NotificationPreferencesResource { + /// Delete a notification preference + pub async fn remove(&self) -> Result<()> { + let path = "/api/v1/notification_preferences".to_owned(); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::remove]. + #[cfg(feature = "blocking")] + pub fn remove_blocking(&self) -> Result<()> { + crate::blocking::block_on(self.remove()) + } + /// List notification preferences + pub async fn list(&self) -> Result { + let path = "/api/v1/notification_preferences".to_owned(); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking(&self) -> Result { + crate::blocking::block_on(self.list()) + } + /// Create or update a notification preference + pub async fn replace( + &self, + body: &PutApiV1NotificationPreferencesInput, + ) -> Result { + let path = "/api/v1/notification_preferences".to_owned(); + let request = self.client.request(Method::PUT, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::replace]. + #[cfg(feature = "blocking")] + pub fn replace_blocking( + &self, + body: &PutApiV1NotificationPreferencesInput, + ) -> Result { + crate::blocking::block_on(self.replace(body)) + } +} + +/// notifications API resource. +#[derive(Clone)] +pub struct NotificationsResource { + client: Client, +} + +impl NotificationsResource { + /// List a user's notifications + pub async fn list( + &self, + params: Option<&GetApiV1NotificationsParams>, + ) -> Result { + let path = "/api/v1/notifications".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1NotificationsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Mark all notifications as read + pub async fn read_all(&self) -> Result<()> { + let path = "/api/v1/notifications/read_all".to_owned(); + let request = self.client.request(Method::POST, &path); + request.send_empty().await + } + /// Blocking variant of [Self::read_all]. + #[cfg(feature = "blocking")] + pub fn read_all_blocking(&self) -> Result<()> { + crate::blocking::block_on(self.read_all()) + } + /// Send a custom notification to a user + pub async fn send(&self, body: &PostApiV1NotificationsSendInput) -> Result { + let path = "/api/v1/notifications/send".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::send]. + #[cfg(feature = "blocking")] + pub fn send_blocking(&self, body: &PostApiV1NotificationsSendInput) -> Result { + crate::blocking::block_on(self.send(body)) + } + /// Get the unread notification count + pub async fn unread_count(&self) -> Result { + let path = "/api/v1/notifications/unread_count".to_owned(); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::unread_count]. + #[cfg(feature = "blocking")] + pub fn unread_count_blocking(&self) -> Result { + crate::blocking::block_on(self.unread_count()) + } + /// Archive a notification + pub async fn archive(&self, notification: &str) -> Result<()> { + let mut path = "/api/v1/notifications/{notification}/archive".to_owned(); + path = path.replace("{notification}", &crate::encode_path(notification)); + let request = self.client.request(Method::POST, &path); + request.send_empty().await + } + /// Blocking variant of [Self::archive]. + #[cfg(feature = "blocking")] + pub fn archive_blocking(&self, notification: &str) -> Result<()> { + crate::blocking::block_on(self.archive(notification)) + } + /// Mark a notification as read + pub async fn read(&self, notification: &str) -> Result<()> { + let mut path = "/api/v1/notifications/{notification}/read".to_owned(); + path = path.replace("{notification}", &crate::encode_path(notification)); + let request = self.client.request(Method::POST, &path); + request.send_empty().await + } + /// Blocking variant of [Self::read]. + #[cfg(feature = "blocking")] + pub fn read_blocking(&self, notification: &str) -> Result<()> { + crate::blocking::block_on(self.read(notification)) + } + /// Unarchive a notification + pub async fn unarchive(&self, notification: &str) -> Result<()> { + let mut path = "/api/v1/notifications/{notification}/unarchive".to_owned(); + path = path.replace("{notification}", &crate::encode_path(notification)); + let request = self.client.request(Method::POST, &path); + request.send_empty().await + } + /// Blocking variant of [Self::unarchive]. + #[cfg(feature = "blocking")] + pub fn unarchive_blocking(&self, notification: &str) -> Result<()> { + crate::blocking::block_on(self.unarchive(notification)) + } +} + +/// orgs API resource. +#[derive(Clone)] +pub struct OrgsResource { + client: Client, +} + +impl OrgsResource { + /// Search organizations + pub async fn list(&self, params: Option<&GetApiV1OrgsParams>) -> Result { + let path = "/api/v1/orgs".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1OrgsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } +} + +/// private_service_definitions API resource. +#[derive(Clone)] +pub struct PrivateServiceDefinitionsResource { + client: Client, +} + +impl PrivateServiceDefinitionsResource { + /// Download an enrolled private service definition + pub async fn get(&self, app_id: &str, private_service_id: &str) -> Result { + let mut path = + "/api/v1/private_service_definitions/{app_id}/{private_service_id}".to_owned(); + path = path.replace("{app_id}", &crate::encode_path(app_id)); + path = path.replace( + "{private_service_id}", + &crate::encode_path(private_service_id), + ); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, app_id: &str, private_service_id: &str) -> Result { + crate::blocking::block_on(self.get(app_id, private_service_id)) + } +} + +/// private_service_enrollments API resource. +#[derive(Clone)] +pub struct PrivateServiceEnrollmentsResource { + client: Client, +} + +impl PrivateServiceEnrollmentsResource { + /// List private service enrollments + pub async fn list( + &self, + params: Option<&GetApiV1PrivateServiceEnrollmentsParams>, + ) -> Result { + let path = "/api/v1/private_service_enrollments".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1PrivateServiceEnrollmentsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create a private service enrollment + pub async fn create( + &self, + body: &PostApiV1PrivateServiceEnrollmentsInput, + ) -> Result { + let path = "/api/v1/private_service_enrollments".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking( + &self, + body: &PostApiV1PrivateServiceEnrollmentsInput, + ) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Retrieve a private service enrollment + pub async fn get( + &self, + private_service_enrollment_id: &str, + params: Option<&GetApiV1PrivateServiceEnrollmentsPrivateServiceEnrollmentIdParams>, + ) -> Result { + let mut path = + "/api/v1/private_service_enrollments/{private_service_enrollment_id}".to_owned(); + path = path.replace( + "{private_service_enrollment_id}", + &crate::encode_path(private_service_enrollment_id), + ); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking( + &self, + private_service_enrollment_id: &str, + params: Option<&GetApiV1PrivateServiceEnrollmentsPrivateServiceEnrollmentIdParams>, + ) -> Result { + crate::blocking::block_on(self.get(private_service_enrollment_id, params)) + } +} + +/// private_services API resource. +#[derive(Clone)] +pub struct PrivateServicesResource { + client: Client, +} + +impl PrivateServicesResource { + /// List private services + pub async fn list( + &self, + params: Option<&GetApiV1PrivateServicesParams>, + ) -> Result { + let path = "/api/v1/private_services".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1PrivateServicesParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create a private service + pub async fn create(&self, body: &PostApiV1PrivateServicesInput) -> Result { + let path = "/api/v1/private_services".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1PrivateServicesInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Retrieve a private service + pub async fn get( + &self, + private_service_id: &str, + params: Option<&GetApiV1PrivateServicesPrivateServiceIdParams>, + ) -> Result { + let mut path = "/api/v1/private_services/{private_service_id}".to_owned(); + path = path.replace( + "{private_service_id}", + &crate::encode_path(private_service_id), + ); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking( + &self, + private_service_id: &str, + params: Option<&GetApiV1PrivateServicesPrivateServiceIdParams>, + ) -> Result { + crate::blocking::block_on(self.get(private_service_id, params)) + } +} + +/// sandboxes API resource. +#[derive(Clone)] +pub struct SandboxesResource { + client: Client, +} + +impl SandboxesResource { + /// Create a sandbox + pub async fn create(&self, body: &PostApiV1SandboxesInput) -> Result { + let path = "/api/v1/sandboxes".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1SandboxesInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Delete a sandbox + pub async fn delete(&self, sandbox: &str) -> Result<()> { + let mut path = "/api/v1/sandboxes/{sandbox}".to_owned(); + path = path.replace("{sandbox}", &crate::encode_path(sandbox)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, sandbox: &str) -> Result<()> { + crate::blocking::block_on(self.delete(sandbox)) + } + /// Retrieve a sandbox + pub async fn get(&self, sandbox: &str) -> Result { + let mut path = "/api/v1/sandboxes/{sandbox}".to_owned(); + path = path.replace("{sandbox}", &crate::encode_path(sandbox)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, sandbox: &str) -> Result { + crate::blocking::block_on(self.get(sandbox)) + } + /// Create a sandbox key + pub async fn keys( + &self, + sandbox: &str, + body: &PostApiV1SandboxesSandboxKeysInput, + ) -> Result { + let mut path = "/api/v1/sandboxes/{sandbox}/keys".to_owned(); + path = path.replace("{sandbox}", &crate::encode_path(sandbox)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::keys]. + #[cfg(feature = "blocking")] + pub fn keys_blocking( + &self, + sandbox: &str, + body: &PostApiV1SandboxesSandboxKeysInput, + ) -> Result { + crate::blocking::block_on(self.keys(sandbox, body)) + } +} + +/// slack_channel_bindings API resource. +#[derive(Clone)] +pub struct SlackChannelBindingsResource { + client: Client, +} + +impl SlackChannelBindingsResource { + /// List Slack channel bindings + pub async fn list( + &self, + params: Option<&GetApiV1SlackChannelBindingsParams>, + ) -> Result { + let path = "/api/v1/slack_channel_bindings".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1SlackChannelBindingsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create or update a Slack channel binding + pub async fn create( + &self, + body: &PostApiV1SlackChannelBindingsInput, + ) -> Result { + let path = "/api/v1/slack_channel_bindings".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking( + &self, + body: &PostApiV1SlackChannelBindingsInput, + ) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Start adding a customer over Slack Connect + pub async fn provision( + &self, + body: &PostApiV1SlackChannelBindingsProvisionInput, + ) -> Result { + let path = "/api/v1/slack_channel_bindings/provision".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::provision]. + #[cfg(feature = "blocking")] + pub fn provision_blocking( + &self, + body: &PostApiV1SlackChannelBindingsProvisionInput, + ) -> Result { + crate::blocking::block_on(self.provision(body)) + } + /// Delete a Slack channel binding + pub async fn delete( + &self, + channel: &str, + ) -> Result { + let mut path = "/api/v1/slack_channel_bindings/{channel}".to_owned(); + path = path.replace("{channel}", &crate::encode_path(channel)); + let request = self.client.request(Method::DELETE, &path); + request.send().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking( + &self, + channel: &str, + ) -> Result { + crate::blocking::block_on(self.delete(channel)) + } + /// Retrieve a Slack channel binding + pub async fn get( + &self, + channel: &str, + params: &GetApiV1SlackChannelBindingsChannelParams, + ) -> Result { + let mut path = "/api/v1/slack_channel_bindings/{channel}".to_owned(); + path = path.replace("{channel}", &crate::encode_path(channel)); + let request = self.client.request(Method::GET, &path); + let request = request.query(params)?; + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking( + &self, + channel: &str, + params: &GetApiV1SlackChannelBindingsChannelParams, + ) -> Result { + crate::blocking::block_on(self.get(channel, params)) + } + /// List delivery outcomes for a Slack channel + pub async fn delivery_outcomes( + &self, + channel: &str, + params: Option<&GetApiV1SlackChannelBindingsChannelDeliveryOutcomesParams>, + ) -> Result { + let mut path = "/api/v1/slack_channel_bindings/{channel}/delivery_outcomes".to_owned(); + path = path.replace("{channel}", &crate::encode_path(channel)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::delivery_outcomes]. + #[cfg(feature = "blocking")] + pub fn delivery_outcomes_blocking( + &self, + channel: &str, + params: Option<&GetApiV1SlackChannelBindingsChannelDeliveryOutcomesParams>, + ) -> Result { + crate::blocking::block_on(self.delivery_outcomes(channel, params)) + } + /// Point a Slack channel's deposit pipe at a staging thread, or turn it off + pub async fn deposit_thread( + &self, + channel: &str, + body: &PostApiV1SlackChannelBindingsChannelDepositThreadInput, + ) -> Result { + let mut path = "/api/v1/slack_channel_bindings/{channel}/deposit_thread".to_owned(); + path = path.replace("{channel}", &crate::encode_path(channel)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::deposit_thread]. + #[cfg(feature = "blocking")] + pub fn deposit_thread_blocking( + &self, + channel: &str, + body: &PostApiV1SlackChannelBindingsChannelDepositThreadInput, + ) -> Result { + crate::blocking::block_on(self.deposit_thread(channel, body)) + } +} + +/// solution_categories API resource. +#[derive(Clone)] +pub struct SolutionCategoriesResource { + client: Client, +} + +impl SolutionCategoriesResource { + /// List solution categories + pub async fn list( + &self, + params: Option<&GetApiV1SolutionCategoriesParams>, + ) -> Result { + let path = "/api/v1/solution_categories".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1SolutionCategoriesParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } +} + +/// solution_instances API resource. +#[derive(Clone)] +pub struct SolutionInstancesResource { + client: Client, +} + +impl SolutionInstancesResource { + /// List customer solution instances + pub async fn list( + &self, + params: &GetApiV1SolutionInstancesParams, + ) -> Result { + let path = "/api/v1/solution_instances".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = request.query(params)?; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: &GetApiV1SolutionInstancesParams, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } +} + +/// solution_tags API resource. +#[derive(Clone)] +pub struct SolutionTagsResource { + client: Client, +} + +impl SolutionTagsResource { + /// List solution tags + pub async fn list( + &self, + params: Option<&GetApiV1SolutionTagsParams>, + ) -> Result { + let path = "/api/v1/solution_tags".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1SolutionTagsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } +} + +/// solutions API resource. +#[derive(Clone)] +pub struct SolutionsResource { + client: Client, +} + +impl SolutionsResource { + /// List Solutions + pub async fn list( + &self, + params: Option<&GetApiV1SolutionsParams>, + ) -> Result { + let path = "/api/v1/solutions".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1SolutionsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Import a Solution into the library + pub async fn create(&self, body: &PostApiV1SolutionsInput) -> Result { + let path = "/api/v1/solutions".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking( + &self, + body: &PostApiV1SolutionsInput, + ) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Delete a Solution + pub async fn delete(&self, solution: &str) -> Result<()> { + let mut path = "/api/v1/solutions/{solution}".to_owned(); + path = path.replace("{solution}", &crate::encode_path(solution)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, solution: &str) -> Result<()> { + crate::blocking::block_on(self.delete(solution)) + } + /// Retrieve a Solution + pub async fn get(&self, solution: &str) -> Result { + let mut path = "/api/v1/solutions/{solution}".to_owned(); + path = path.replace("{solution}", &crate::encode_path(solution)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, solution: &str) -> Result { + crate::blocking::block_on(self.get(solution)) + } + /// Preview Solution delete impact + pub async fn dependents(&self, solution: &str) -> Result { + let mut path = "/api/v1/solutions/{solution}/dependents".to_owned(); + path = path.replace("{solution}", &crate::encode_path(solution)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::dependents]. + #[cfg(feature = "blocking")] + pub fn dependents_blocking(&self, solution: &str) -> Result { + crate::blocking::block_on(self.dependents(solution)) + } + /// Fetch a Solution cover image or gallery screenshot + pub async fn image( + &self, + solution: &str, + params: &GetApiV1SolutionsSolutionImageParams, + ) -> Result { + let mut path = "/api/v1/solutions/{solution}/image".to_owned(); + path = path.replace("{solution}", &crate::encode_path(solution)); + let request = self.client.request(Method::GET, &path); + let request = request.query(params)?; + request.send_raw().await + } + /// Blocking variant of [Self::image]. + #[cfg(feature = "blocking")] + pub fn image_blocking( + &self, + solution: &str, + params: &GetApiV1SolutionsSolutionImageParams, + ) -> Result { + crate::blocking::block_on(self.image(solution, params)) + } + /// Install a Solution + pub async fn install( + &self, + solution: &str, + body: &PostApiV1SolutionsSolutionInstallInput, + ) -> Result { + let mut path = "/api/v1/solutions/{solution}/install".to_owned(); + path = path.replace("{solution}", &crate::encode_path(solution)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::install]. + #[cfg(feature = "blocking")] + pub fn install_blocking( + &self, + solution: &str, + body: &PostApiV1SolutionsSolutionInstallInput, + ) -> Result { + crate::blocking::block_on(self.install(solution, body)) + } + /// Retrieve a Solution README or asset + pub async fn readme( + &self, + solution: &str, + params: &GetApiV1SolutionsSolutionReadmeParams, + ) -> Result { + let mut path = "/api/v1/solutions/{solution}/readme".to_owned(); + path = path.replace("{solution}", &crate::encode_path(solution)); + let request = self.client.request(Method::GET, &path); + let request = request.query(params)?; + request.send_raw().await + } + /// Blocking variant of [Self::readme]. + #[cfg(feature = "blocking")] + pub fn readme_blocking( + &self, + solution: &str, + params: &GetApiV1SolutionsSolutionReadmeParams, + ) -> Result { + crate::blocking::block_on(self.readme(solution, params)) + } + /// Upgrade an installed Solution + pub async fn upgrade( + &self, + solution: &str, + body: &PostApiV1SolutionsSolutionUpgradeInput, + ) -> Result { + let mut path = "/api/v1/solutions/{solution}/upgrade".to_owned(); + path = path.replace("{solution}", &crate::encode_path(solution)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::upgrade]. + #[cfg(feature = "blocking")] + pub fn upgrade_blocking( + &self, + solution: &str, + body: &PostApiV1SolutionsSolutionUpgradeInput, + ) -> Result { + crate::blocking::block_on(self.upgrade(solution, body)) + } + /// Track a Solution detail-page view + pub async fn view( + &self, + solution: &str, + body: &PostApiV1SolutionsSolutionViewInput, + ) -> Result<()> { + let mut path = "/api/v1/solutions/{solution}/view".to_owned(); + path = path.replace("{solution}", &crate::encode_path(solution)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send_empty().await + } + /// Blocking variant of [Self::view]. + #[cfg(feature = "blocking")] + pub fn view_blocking( + &self, + solution: &str, + body: &PostApiV1SolutionsSolutionViewInput, + ) -> Result<()> { + crate::blocking::block_on(self.view(solution, body)) + } +} + +/// status API resource. +#[derive(Clone)] +pub struct StatusResource { + client: Client, +} + +impl StatusResource { + /// Check API token status + pub async fn ping(&self) -> Result { + let path = "/api/v1/status/ping".to_owned(); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::ping]. + #[cfg(feature = "blocking")] + pub fn ping_blocking(&self) -> Result { + crate::blocking::block_on(self.ping()) + } +} + +/// tasks API resource. +#[derive(Clone)] +pub struct TasksResource { + client: Client, +} + +impl TasksResource { + /// Access the nested blockers resource. + pub fn blockers(&self, task: &str) -> TasksBlockersResource { + TasksBlockersResource { + client: self.client.clone(), + task: task.to_owned(), + } + } + /// Access the nested comments resource. + pub fn comments(&self, task: &str) -> TasksCommentsResource { + TasksCommentsResource { + client: self.client.clone(), + task: task.to_owned(), + } + } + /// Access the nested lease resource. + pub fn lease(&self, task: &str) -> TasksLeaseResource { + TasksLeaseResource { + client: self.client.clone(), + task: task.to_owned(), + } + } + /// Access the nested links resource. + pub fn links(&self, task: &str) -> TasksLinksResource { + TasksLinksResource { + client: self.client.clone(), + task: task.to_owned(), + } + } + /// Delete a task + pub async fn delete(&self, task: &str) -> Result<()> { + let mut path = "/api/v1/tasks/{task}".to_owned(); + path = path.replace("{task}", &crate::encode_path(task)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, task: &str) -> Result<()> { + crate::blocking::block_on(self.delete(task)) + } + /// Retrieve a task + pub async fn get(&self, task: &str, params: Option<&GetApiV1TasksTaskParams>) -> Result { + let mut path = "/api/v1/tasks/{task}".to_owned(); + path = path.replace("{task}", &crate::encode_path(task)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking( + &self, + task: &str, + params: Option<&GetApiV1TasksTaskParams>, + ) -> Result { + crate::blocking::block_on(self.get(task, params)) + } + /// Update a task + pub async fn replace(&self, task: &str, body: &PutApiV1TasksTaskInput) -> Result { + let mut path = "/api/v1/tasks/{task}".to_owned(); + path = path.replace("{task}", &crate::encode_path(task)); + let request = self.client.request(Method::PUT, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::replace]. + #[cfg(feature = "blocking")] + pub fn replace_blocking(&self, task: &str, body: &PutApiV1TasksTaskInput) -> Result { + crate::blocking::block_on(self.replace(task, body)) + } + /// List a task's activity + pub async fn activity( + &self, + task: &str, + params: Option<&GetApiV1TasksTaskActivityParams>, + ) -> Result { + let mut path = "/api/v1/tasks/{task}/activity".to_owned(); + path = path.replace("{task}", &crate::encode_path(task)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::activity]. + #[cfg(feature = "blocking")] + pub fn activity_blocking( + &self, + task: &str, + params: Option<&GetApiV1TasksTaskActivityParams>, + ) -> Result { + crate::blocking::block_on(self.activity(task, params)) + } + /// List the tasks a task blocks + pub async fn blocking( + &self, + task: &str, + params: Option<&GetApiV1TasksTaskBlockingParams>, + ) -> Result { + let mut path = "/api/v1/tasks/{task}/blocking".to_owned(); + path = path.replace("{task}", &crate::encode_path(task)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::blocking]. + #[cfg(feature = "blocking")] + pub fn blocking_blocking( + &self, + task: &str, + params: Option<&GetApiV1TasksTaskBlockingParams>, + ) -> Result { + crate::blocking::block_on(self.blocking(task, params)) + } + /// List a task's subtasks + pub async fn subtasks( + &self, + task: &str, + params: Option<&GetApiV1TasksTaskSubtasksParams>, + ) -> Result { + let mut path = "/api/v1/tasks/{task}/subtasks".to_owned(); + path = path.replace("{task}", &crate::encode_path(task)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::subtasks]. + #[cfg(feature = "blocking")] + pub fn subtasks_blocking( + &self, + task: &str, + params: Option<&GetApiV1TasksTaskSubtasksParams>, + ) -> Result { + crate::blocking::block_on(self.subtasks(task, params)) + } +} + +/// blockers API resource. +#[derive(Clone)] +pub struct TasksBlockersResource { + client: Client, + /// Bound task scope. + task: String, +} + +impl TasksBlockersResource { + /// List a task's blockers + pub async fn list( + &self, + params: Option<&GetApiV1TasksTaskBlockersParams>, + ) -> Result { + let mut path = "/api/v1/tasks/{task}/blockers".to_owned(); + path = path.replace("{task}", &crate::encode_path(self.task.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1TasksTaskBlockersParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Mark a task as blocked by another task + pub async fn create(&self, body: &PostApiV1TasksTaskBlockersInput) -> Result { + let mut path = "/api/v1/tasks/{task}/blockers".to_owned(); + path = path.replace("{task}", &crate::encode_path(self.task.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1TasksTaskBlockersInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Remove a blocker from a task + pub async fn delete(&self, blocker: &str) -> Result<()> { + let mut path = "/api/v1/tasks/{task}/blockers/{blocker}".to_owned(); + path = path.replace("{task}", &crate::encode_path(self.task.as_str())); + path = path.replace("{blocker}", &crate::encode_path(blocker)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, blocker: &str) -> Result<()> { + crate::blocking::block_on(self.delete(blocker)) + } +} + +/// comments API resource. +#[derive(Clone)] +pub struct TasksCommentsResource { + client: Client, + /// Bound task scope. + task: String, +} + +impl TasksCommentsResource { + /// List comments on a task + pub async fn list( + &self, + params: Option<&GetApiV1TasksTaskCommentsParams>, + ) -> Result { + let mut path = "/api/v1/tasks/{task}/comments".to_owned(); + path = path.replace("{task}", &crate::encode_path(self.task.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1TasksTaskCommentsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create a comment on a task + pub async fn create(&self, body: &PostApiV1TasksTaskCommentsInput) -> Result { + let mut path = "/api/v1/tasks/{task}/comments".to_owned(); + path = path.replace("{task}", &crate::encode_path(self.task.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1TasksTaskCommentsInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Delete a task comment + pub async fn delete(&self, comment: &str) -> Result<()> { + let mut path = "/api/v1/tasks/{task}/comments/{comment}".to_owned(); + path = path.replace("{task}", &crate::encode_path(self.task.as_str())); + path = path.replace("{comment}", &crate::encode_path(comment)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, comment: &str) -> Result<()> { + crate::blocking::block_on(self.delete(comment)) + } + /// Update a task comment + pub async fn replace( + &self, + comment: &str, + body: &PutApiV1TasksTaskCommentsCommentInput, + ) -> Result { + let mut path = "/api/v1/tasks/{task}/comments/{comment}".to_owned(); + path = path.replace("{task}", &crate::encode_path(self.task.as_str())); + path = path.replace("{comment}", &crate::encode_path(comment)); + let request = self.client.request(Method::PUT, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::replace]. + #[cfg(feature = "blocking")] + pub fn replace_blocking( + &self, + comment: &str, + body: &PutApiV1TasksTaskCommentsCommentInput, + ) -> Result { + crate::blocking::block_on(self.replace(comment, body)) + } +} + +/// lease API resource. +#[derive(Clone)] +pub struct TasksLeaseResource { + client: Client, + /// Bound task scope. + task: String, +} + +impl TasksLeaseResource { + /// Release a task session lease + pub async fn remove(&self) -> Result<()> { + let mut path = "/api/v1/tasks/{task}/lease".to_owned(); + path = path.replace("{task}", &crate::encode_path(self.task.as_str())); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::remove]. + #[cfg(feature = "blocking")] + pub fn remove_blocking(&self) -> Result<()> { + crate::blocking::block_on(self.remove()) + } + /// Retrieve a task's current session lease + pub async fn list(&self) -> Result { + let mut path = "/api/v1/tasks/{task}/lease".to_owned(); + path = path.replace("{task}", &crate::encode_path(self.task.as_str())); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking(&self) -> Result { + crate::blocking::block_on(self.list()) + } + /// Claim a task for a coding session + pub async fn create(&self, body: &PostApiV1TasksTaskLeaseInput) -> Result { + let mut path = "/api/v1/tasks/{task}/lease".to_owned(); + path = path.replace("{task}", &crate::encode_path(self.task.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1TasksTaskLeaseInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Renew a task session lease + pub async fn renew( + &self, + body: &PostApiV1TasksTaskLeaseRenewInput, + ) -> Result { + let mut path = "/api/v1/tasks/{task}/lease/renew".to_owned(); + path = path.replace("{task}", &crate::encode_path(self.task.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::renew]. + #[cfg(feature = "blocking")] + pub fn renew_blocking( + &self, + body: &PostApiV1TasksTaskLeaseRenewInput, + ) -> Result { + crate::blocking::block_on(self.renew(body)) + } +} + +/// links API resource. +#[derive(Clone)] +pub struct TasksLinksResource { + client: Client, + /// Bound task scope. + task: String, +} + +impl TasksLinksResource { + /// Remove an external link from a task + pub async fn remove(&self) -> Result<()> { + let mut path = "/api/v1/tasks/{task}/links".to_owned(); + path = path.replace("{task}", &crate::encode_path(self.task.as_str())); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::remove]. + #[cfg(feature = "blocking")] + pub fn remove_blocking(&self) -> Result<()> { + crate::blocking::block_on(self.remove()) + } + /// Add an external link to a task + pub async fn create( + &self, + body: &PostApiV1TasksTaskLinksInput, + ) -> Result> { + let mut path = "/api/v1/tasks/{task}/links".to_owned(); + path = path.replace("{task}", &crate::encode_path(self.task.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking( + &self, + body: &PostApiV1TasksTaskLinksInput, + ) -> Result> { + crate::blocking::block_on(self.create(body)) + } +} + +/// team_memberships API resource. +#[derive(Clone)] +pub struct TeamMembershipsResource { + client: Client, +} + +impl TeamMembershipsResource { + /// List team memberships + pub async fn list( + &self, + params: Option<&GetApiV1TeamMembershipsParams>, + ) -> Result { + let path = "/api/v1/team_memberships".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1TeamMembershipsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Remove a team membership by ID + pub async fn delete(&self, team_membership: &str) -> Result<()> { + let mut path = "/api/v1/team_memberships/{team_membership}".to_owned(); + path = path.replace("{team_membership}", &crate::encode_path(team_membership)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, team_membership: &str) -> Result<()> { + crate::blocking::block_on(self.delete(team_membership)) + } +} + +/// teams API resource. +#[derive(Clone)] +pub struct TeamsResource { + client: Client, +} + +impl TeamsResource { + /// Access the nested custom_objects resource. + pub fn custom_objects(&self, team: &str) -> TeamsCustomObjectsResource { + TeamsCustomObjectsResource { + client: self.client.clone(), + team: team.to_owned(), + } + } + /// Access the nested members resource. + pub fn members(&self, team: &str) -> TeamsMembersResource { + TeamsMembersResource { + client: self.client.clone(), + team: team.to_owned(), + } + } + /// Access the nested tasks resource. + pub fn tasks(&self, team: &str) -> TeamsTasksResource { + TeamsTasksResource { + client: self.client.clone(), + team: team.to_owned(), + } + } + /// Access the nested threads resource. + pub fn threads(&self, team: &str) -> TeamsThreadsResource { + TeamsThreadsResource { + client: self.client.clone(), + team: team.to_owned(), + } + } + /// List teams + pub async fn list( + &self, + params: Option<&GetApiV1TeamsParams>, + ) -> Result { + let path = "/api/v1/teams".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1TeamsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create a team + pub async fn create(&self, body: &PostApiV1TeamsInput) -> Result { + let path = "/api/v1/teams".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1TeamsInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Join a team with an invite code + pub async fn join_by_code(&self, body: &PostApiV1TeamsJoinByCodeInput) -> Result { + let path = "/api/v1/teams/join_by_code".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::join_by_code]. + #[cfg(feature = "blocking")] + pub fn join_by_code_blocking(&self, body: &PostApiV1TeamsJoinByCodeInput) -> Result { + crate::blocking::block_on(self.join_by_code(body)) + } + /// Delete a team + pub async fn delete(&self, team: &str) -> Result<()> { + let mut path = "/api/v1/teams/{team}".to_owned(); + path = path.replace("{team}", &crate::encode_path(team)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, team: &str) -> Result<()> { + crate::blocking::block_on(self.delete(team)) + } + /// Retrieve a team + pub async fn get(&self, team: &str) -> Result { + let mut path = "/api/v1/teams/{team}".to_owned(); + path = path.replace("{team}", &crate::encode_path(team)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, team: &str) -> Result { + crate::blocking::block_on(self.get(team)) + } + /// Update a team + pub async fn update(&self, team: &str, body: &PatchApiV1TeamsTeamInput) -> Result { + let mut path = "/api/v1/teams/{team}".to_owned(); + path = path.replace("{team}", &crate::encode_path(team)); + let request = self.client.request(Method::PATCH, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::update]. + #[cfg(feature = "blocking")] + pub fn update_blocking(&self, team: &str, body: &PatchApiV1TeamsTeamInput) -> Result { + crate::blocking::block_on(self.update(team, body)) + } + /// List a team's artifacts + pub async fn artifacts(&self, team: &str) -> Result { + let mut path = "/api/v1/teams/{team}/artifacts".to_owned(); + path = path.replace("{team}", &crate::encode_path(team)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::artifacts]. + #[cfg(feature = "blocking")] + pub fn artifacts_blocking(&self, team: &str) -> Result { + crate::blocking::block_on(self.artifacts(team)) + } + /// Create a team invite + pub async fn invite(&self, team: &str) -> Result { + let mut path = "/api/v1/teams/{team}/invite".to_owned(); + path = path.replace("{team}", &crate::encode_path(team)); + let request = self.client.request(Method::POST, &path); + request.send().await + } + /// Blocking variant of [Self::invite]. + #[cfg(feature = "blocking")] + pub fn invite_blocking(&self, team: &str) -> Result { + crate::blocking::block_on(self.invite(team)) + } + /// Create a team invite (server-to-server) + pub async fn invites(&self, team: &str) -> Result { + let mut path = "/api/v1/teams/{team}/invites".to_owned(); + path = path.replace("{team}", &crate::encode_path(team)); + let request = self.client.request(Method::POST, &path); + request.send().await + } + /// Blocking variant of [Self::invites]. + #[cfg(feature = "blocking")] + pub fn invites_blocking(&self, team: &str) -> Result { + crate::blocking::block_on(self.invites(team)) + } + /// Join a team + pub async fn join(&self, team: &str, body: &PostApiV1TeamsTeamJoinInput) -> Result<()> { + let mut path = "/api/v1/teams/{team}/join".to_owned(); + path = path.replace("{team}", &crate::encode_path(team)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send_empty().await + } + /// Blocking variant of [Self::join]. + #[cfg(feature = "blocking")] + pub fn join_blocking(&self, team: &str, body: &PostApiV1TeamsTeamJoinInput) -> Result<()> { + crate::blocking::block_on(self.join(team, body)) + } + /// Leave a team + pub async fn leave(&self, team: &str) -> Result<()> { + let mut path = "/api/v1/teams/{team}/leave".to_owned(); + path = path.replace("{team}", &crate::encode_path(team)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::leave]. + #[cfg(feature = "blocking")] + pub fn leave_blocking(&self, team: &str) -> Result<()> { + crate::blocking::block_on(self.leave(team)) + } + /// List task assignees for a team + pub async fn task_assignees( + &self, + team: &str, + params: Option<&GetApiV1TeamsTeamTaskAssigneesParams>, + ) -> Result { + let mut path = "/api/v1/teams/{team}/task_assignees".to_owned(); + path = path.replace("{team}", &crate::encode_path(team)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::task_assignees]. + #[cfg(feature = "blocking")] + pub fn task_assignees_blocking( + &self, + team: &str, + params: Option<&GetApiV1TeamsTeamTaskAssigneesParams>, + ) -> Result { + crate::blocking::block_on(self.task_assignees(team, params)) + } +} + +/// custom_objects API resource. +#[derive(Clone)] +pub struct TeamsCustomObjectsResource { + client: Client, + /// Bound team scope. + team: String, +} + +impl TeamsCustomObjectsResource { + /// List a team's custom objects + pub async fn list( + &self, + params: &GetApiV1TeamsTeamCustomObjectsParams, + ) -> Result { + let mut path = "/api/v1/teams/{team}/custom_objects".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::GET, &path); + let request = request.query(params)?; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: &GetApiV1TeamsTeamCustomObjectsParams, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create a team custom object + pub async fn create( + &self, + body: &PostApiV1TeamsTeamCustomObjectsInput, + ) -> Result { + let mut path = "/api/v1/teams/{team}/custom_objects".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking( + &self, + body: &PostApiV1TeamsTeamCustomObjectsInput, + ) -> Result { + crate::blocking::block_on(self.create(body)) + } +} + +/// members API resource. +#[derive(Clone)] +pub struct TeamsMembersResource { + client: Client, + /// Bound team scope. + team: String, +} + +impl TeamsMembersResource { + /// Remove a member or org from a team + pub async fn remove(&self) -> Result<()> { + let mut path = "/api/v1/teams/{team}/members".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::remove]. + #[cfg(feature = "blocking")] + pub fn remove_blocking(&self) -> Result<()> { + crate::blocking::block_on(self.remove()) + } + /// List members of a team + pub async fn list(&self) -> Result { + let mut path = "/api/v1/teams/{team}/members".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking(&self) -> Result { + crate::blocking::block_on(self.list()) + } + /// Add a member to a team + pub async fn create(&self, body: &PostApiV1TeamsTeamMembersInput) -> Result { + let mut path = "/api/v1/teams/{team}/members".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1TeamsTeamMembersInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Update a team member's role + pub async fn update( + &self, + user: &str, + body: &PatchApiV1TeamsTeamMembersUserInput, + ) -> Result { + let mut path = "/api/v1/teams/{team}/members/{user}".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + path = path.replace("{user}", &crate::encode_path(user)); + let request = self.client.request(Method::PATCH, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::update]. + #[cfg(feature = "blocking")] + pub fn update_blocking( + &self, + user: &str, + body: &PatchApiV1TeamsTeamMembersUserInput, + ) -> Result { + crate::blocking::block_on(self.update(user, body)) + } +} + +/// tasks API resource. +#[derive(Clone)] +pub struct TeamsTasksResource { + client: Client, + /// Bound team scope. + team: String, +} + +impl TeamsTasksResource { + /// List an owner's tasks + pub async fn list( + &self, + params: Option<&GetApiV1TeamsTeamTasksParams>, + ) -> Result { + let mut path = "/api/v1/teams/{team}/tasks".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1TeamsTeamTasksParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create a task for an owner + pub async fn create(&self, body: &PostApiV1TeamsTeamTasksInput) -> Result { + let mut path = "/api/v1/teams/{team}/tasks".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1TeamsTeamTasksInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// List task blocker cycles + pub async fn blocker_cycles( + &self, + params: Option<&GetApiV1TeamsTeamTasksBlockerCyclesParams>, + ) -> Result { + let mut path = "/api/v1/teams/{team}/tasks/blocker_cycles".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::blocker_cycles]. + #[cfg(feature = "blocking")] + pub fn blocker_cycles_blocking( + &self, + params: Option<&GetApiV1TeamsTeamTasksBlockerCyclesParams>, + ) -> Result { + crate::blocking::block_on(self.blocker_cycles(params)) + } + /// Get task activity metrics for a team + pub async fn metrics( + &self, + params: Option<&GetApiV1TeamsTeamTasksMetricsParams>, + ) -> Result { + let mut path = "/api/v1/teams/{team}/tasks/metrics".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::metrics]. + #[cfg(feature = "blocking")] + pub fn metrics_blocking( + &self, + params: Option<&GetApiV1TeamsTeamTasksMetricsParams>, + ) -> Result { + crate::blocking::block_on(self.metrics(params)) + } + /// List an owner's ready tasks + pub async fn ready( + &self, + params: Option<&GetApiV1TeamsTeamTasksReadyParams>, + ) -> Result { + let mut path = "/api/v1/teams/{team}/tasks/ready".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::ready]. + #[cfg(feature = "blocking")] + pub fn ready_blocking( + &self, + params: Option<&GetApiV1TeamsTeamTasksReadyParams>, + ) -> Result { + crate::blocking::block_on(self.ready(params)) + } + /// Search an owner's tasks + pub async fn search( + &self, + params: Option<&GetApiV1TeamsTeamTasksSearchParams>, + ) -> Result { + let mut path = "/api/v1/teams/{team}/tasks/search".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::search]. + #[cfg(feature = "blocking")] + pub fn search_blocking( + &self, + params: Option<&GetApiV1TeamsTeamTasksSearchParams>, + ) -> Result { + crate::blocking::block_on(self.search(params)) + } +} + +/// threads API resource. +#[derive(Clone)] +pub struct TeamsThreadsResource { + client: Client, + /// Bound team scope. + team: String, +} + +impl TeamsThreadsResource { + /// List threads for a team + pub async fn list( + &self, + params: Option<&GetApiV1TeamsTeamThreadsParams>, + ) -> Result { + let mut path = "/api/v1/teams/{team}/threads".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1TeamsTeamThreadsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create a thread for a team + pub async fn create(&self, body: &PostApiV1TeamsTeamThreadsInput) -> Result { + let mut path = "/api/v1/teams/{team}/threads".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1TeamsTeamThreadsInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Get threads-created count for a team + pub async fn metrics( + &self, + params: Option<&GetApiV1TeamsTeamThreadsMetricsParams>, + ) -> Result { + let mut path = "/api/v1/teams/{team}/threads/metrics".to_owned(); + path = path.replace("{team}", &crate::encode_path(self.team.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::metrics]. + #[cfg(feature = "blocking")] + pub fn metrics_blocking( + &self, + params: Option<&GetApiV1TeamsTeamThreadsMetricsParams>, + ) -> Result { + crate::blocking::block_on(self.metrics(params)) + } +} + +/// thread_messages API resource. +#[derive(Clone)] +pub struct ThreadMessagesResource { + client: Client, +} + +impl ThreadMessagesResource { + /// Access the nested reactions resource. + pub fn reactions(&self, message: &str) -> ThreadMessagesReactionsResource { + ThreadMessagesReactionsResource { + client: self.client.clone(), + message: message.to_owned(), + } + } + /// Delete a thread message + pub async fn delete(&self, message: &str) -> Result<()> { + let mut path = "/api/v1/thread_messages/{message}".to_owned(); + path = path.replace("{message}", &crate::encode_path(message)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, message: &str) -> Result<()> { + crate::blocking::block_on(self.delete(message)) + } + /// Retrieve a message + pub async fn get(&self, message: &str) -> Result { + let mut path = "/api/v1/thread_messages/{message}".to_owned(); + path = path.replace("{message}", &crate::encode_path(message)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, message: &str) -> Result { + crate::blocking::block_on(self.get(message)) + } + /// Update a thread message + pub async fn replace( + &self, + message: &str, + body: &PutApiV1ThreadMessagesMessageInput, + ) -> Result { + let mut path = "/api/v1/thread_messages/{message}".to_owned(); + path = path.replace("{message}", &crate::encode_path(message)); + let request = self.client.request(Method::PUT, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::replace]. + #[cfg(feature = "blocking")] + pub fn replace_blocking( + &self, + message: &str, + body: &PutApiV1ThreadMessagesMessageInput, + ) -> Result { + crate::blocking::block_on(self.replace(message, body)) + } + /// List replies to a thread message + pub async fn replies( + &self, + message: &str, + params: Option<&GetApiV1ThreadMessagesMessageRepliesParams>, + ) -> Result { + let mut path = "/api/v1/thread_messages/{message}/replies".to_owned(); + path = path.replace("{message}", &crate::encode_path(message)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::replies]. + #[cfg(feature = "blocking")] + pub fn replies_blocking( + &self, + message: &str, + params: Option<&GetApiV1ThreadMessagesMessageRepliesParams>, + ) -> Result { + crate::blocking::block_on(self.replies(message, params)) + } +} + +/// reactions API resource. +#[derive(Clone)] +pub struct ThreadMessagesReactionsResource { + client: Client, + /// Bound message scope. + message: String, +} + +impl ThreadMessagesReactionsResource { + /// Remove a reaction from a thread message + pub async fn remove(&self) -> Result<()> { + let mut path = "/api/v1/thread_messages/{message}/reactions".to_owned(); + path = path.replace("{message}", &crate::encode_path(self.message.as_str())); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::remove]. + #[cfg(feature = "blocking")] + pub fn remove_blocking(&self) -> Result<()> { + crate::blocking::block_on(self.remove()) + } + /// Add a reaction to a thread message + pub async fn create( + &self, + body: &PostApiV1ThreadMessagesMessageReactionsInput, + ) -> Result { + let mut path = "/api/v1/thread_messages/{message}/reactions".to_owned(); + path = path.replace("{message}", &crate::encode_path(self.message.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking( + &self, + body: &PostApiV1ThreadMessagesMessageReactionsInput, + ) -> Result { + crate::blocking::block_on(self.create(body)) + } +} + +/// threads API resource. +#[derive(Clone)] +pub struct ThreadsResource { + client: Client, +} + +impl ThreadsResource { + /// Access the nested members resource. + pub fn members(&self, thread: &str) -> ThreadsMembersResource { + ThreadsMembersResource { + client: self.client.clone(), + thread: thread.to_owned(), + } + } + /// Access the nested settings resource. + pub fn settings(&self, thread: &str) -> ThreadsSettingsResource { + ThreadsSettingsResource { + client: self.client.clone(), + thread: thread.to_owned(), + } + } + /// Access the nested tags resource. + pub fn tags(&self, thread: &str) -> ThreadsTagsResource { + ThreadsTagsResource { + client: self.client.clone(), + thread: thread.to_owned(), + } + } + /// Delete a thread + pub async fn delete(&self, thread: &str) -> Result<()> { + let mut path = "/api/v1/threads/{thread}".to_owned(); + path = path.replace("{thread}", &crate::encode_path(thread)); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, thread: &str) -> Result<()> { + crate::blocking::block_on(self.delete(thread)) + } + /// Retrieve a thread + pub async fn get(&self, thread: &str) -> Result { + let mut path = "/api/v1/threads/{thread}".to_owned(); + path = path.replace("{thread}", &crate::encode_path(thread)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, thread: &str) -> Result { + crate::blocking::block_on(self.get(thread)) + } + /// Update a thread + pub async fn replace(&self, thread: &str, body: &PutApiV1ThreadsThreadInput) -> Result { + let mut path = "/api/v1/threads/{thread}".to_owned(); + path = path.replace("{thread}", &crate::encode_path(thread)); + let request = self.client.request(Method::PUT, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::replace]. + #[cfg(feature = "blocking")] + pub fn replace_blocking( + &self, + thread: &str, + body: &PutApiV1ThreadsThreadInput, + ) -> Result { + crate::blocking::block_on(self.replace(thread, body)) + } + /// List agents in a thread + pub async fn agents(&self, thread: &str) -> Result { + let mut path = "/api/v1/threads/{thread}/agents".to_owned(); + path = path.replace("{thread}", &crate::encode_path(thread)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::agents]. + #[cfg(feature = "blocking")] + pub fn agents_blocking(&self, thread: &str) -> Result { + crate::blocking::block_on(self.agents(thread)) + } + /// List artifacts for a thread + pub async fn artifacts(&self, thread: &str) -> Result { + let mut path = "/api/v1/threads/{thread}/artifacts".to_owned(); + path = path.replace("{thread}", &crate::encode_path(thread)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::artifacts]. + #[cfg(feature = "blocking")] + pub fn artifacts_blocking( + &self, + thread: &str, + ) -> Result { + crate::blocking::block_on(self.artifacts(thread)) + } + /// Mark a thread as read + pub async fn mark_read( + &self, + thread: &str, + body: &PostApiV1ThreadsThreadMarkReadInput, + ) -> Result<()> { + let mut path = "/api/v1/threads/{thread}/mark_read".to_owned(); + path = path.replace("{thread}", &crate::encode_path(thread)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send_empty().await + } + /// Blocking variant of [Self::mark_read]. + #[cfg(feature = "blocking")] + pub fn mark_read_blocking( + &self, + thread: &str, + body: &PostApiV1ThreadsThreadMarkReadInput, + ) -> Result<()> { + crate::blocking::block_on(self.mark_read(thread, body)) + } + /// List messages in a thread + pub async fn messages( + &self, + thread: &str, + params: Option<&GetApiV1ThreadsThreadMessagesParams>, + ) -> Result { + let mut path = "/api/v1/threads/{thread}/messages".to_owned(); + path = path.replace("{thread}", &crate::encode_path(thread)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::messages]. + #[cfg(feature = "blocking")] + pub fn messages_blocking( + &self, + thread: &str, + params: Option<&GetApiV1ThreadsThreadMessagesParams>, + ) -> Result { + crate::blocking::block_on(self.messages(thread, params)) + } + /// Update a thread's profile picture + pub async fn picture( + &self, + thread: &str, + body: &PutApiV1ThreadsThreadPictureInput, + ) -> Result { + let mut path = "/api/v1/threads/{thread}/picture".to_owned(); + path = path.replace("{thread}", &crate::encode_path(thread)); + let request = self.client.request(Method::PUT, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::picture]. + #[cfg(feature = "blocking")] + pub fn picture_blocking( + &self, + thread: &str, + body: &PutApiV1ThreadsThreadPictureInput, + ) -> Result { + crate::blocking::block_on(self.picture(thread, body)) + } + /// Retrieve a thread's read status + pub async fn read_status( + &self, + thread: &str, + params: Option<&GetApiV1ThreadsThreadReadStatusParams>, + ) -> Result { + let mut path = "/api/v1/threads/{thread}/read_status".to_owned(); + path = path.replace("{thread}", &crate::encode_path(thread)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::read_status]. + #[cfg(feature = "blocking")] + pub fn read_status_blocking( + &self, + thread: &str, + params: Option<&GetApiV1ThreadsThreadReadStatusParams>, + ) -> Result { + crate::blocking::block_on(self.read_status(thread, params)) + } + /// Search messages in a thread + pub async fn search( + &self, + thread: &str, + params: &GetApiV1ThreadsThreadSearchParams, + ) -> Result { + let mut path = "/api/v1/threads/{thread}/search".to_owned(); + path = path.replace("{thread}", &crate::encode_path(thread)); + let request = self.client.request(Method::GET, &path); + let request = request.query(params)?; + request.send().await + } + /// Blocking variant of [Self::search]. + #[cfg(feature = "blocking")] + pub fn search_blocking( + &self, + thread: &str, + params: &GetApiV1ThreadsThreadSearchParams, + ) -> Result { + crate::blocking::block_on(self.search(thread, params)) + } + /// List trajectories for a thread + pub async fn trajectories( + &self, + thread: &str, + params: Option<&GetApiV1ThreadsThreadTrajectoriesParams>, + ) -> Result { + let mut path = "/api/v1/threads/{thread}/trajectories".to_owned(); + path = path.replace("{thread}", &crate::encode_path(thread)); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::trajectories]. + #[cfg(feature = "blocking")] + pub fn trajectories_blocking( + &self, + thread: &str, + params: Option<&GetApiV1ThreadsThreadTrajectoriesParams>, + ) -> Result { + crate::blocking::block_on(self.trajectories(thread, params)) + } +} + +/// members API resource. +#[derive(Clone)] +pub struct ThreadsMembersResource { + client: Client, + /// Bound thread scope. + thread: String, +} + +impl ThreadsMembersResource { + /// Remove a member from a thread + pub async fn remove(&self) -> Result<()> { + let mut path = "/api/v1/threads/{thread}/members".to_owned(); + path = path.replace("{thread}", &crate::encode_path(self.thread.as_str())); + let request = self.client.request(Method::DELETE, &path); + request.send_empty().await + } + /// Blocking variant of [Self::remove]. + #[cfg(feature = "blocking")] + pub fn remove_blocking(&self) -> Result<()> { + crate::blocking::block_on(self.remove()) + } + /// List members of a thread + pub async fn list(&self) -> Result { + let mut path = "/api/v1/threads/{thread}/members".to_owned(); + path = path.replace("{thread}", &crate::encode_path(self.thread.as_str())); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking(&self) -> Result { + crate::blocking::block_on(self.list()) + } + /// Add a member to a thread + pub async fn create(&self, body: &PostApiV1ThreadsThreadMembersInput) -> Result { + let mut path = "/api/v1/threads/{thread}/members".to_owned(); + path = path.replace("{thread}", &crate::encode_path(self.thread.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1ThreadsThreadMembersInput) -> Result { + crate::blocking::block_on(self.create(body)) + } +} + +/// settings API resource. +#[derive(Clone)] +pub struct ThreadsSettingsResource { + client: Client, + /// Bound thread scope. + thread: String, +} + +impl ThreadsSettingsResource { + /// Retrieve thread settings + pub async fn list(&self) -> Result { + let mut path = "/api/v1/threads/{thread}/settings".to_owned(); + path = path.replace("{thread}", &crate::encode_path(self.thread.as_str())); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking(&self) -> Result { + crate::blocking::block_on(self.list()) + } + /// Update thread settings + pub async fn replace( + &self, + body: &PutApiV1ThreadsThreadSettingsInput, + ) -> Result { + let mut path = "/api/v1/threads/{thread}/settings".to_owned(); + path = path.replace("{thread}", &crate::encode_path(self.thread.as_str())); + let request = self.client.request(Method::PUT, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::replace]. + #[cfg(feature = "blocking")] + pub fn replace_blocking( + &self, + body: &PutApiV1ThreadsThreadSettingsInput, + ) -> Result { + crate::blocking::block_on(self.replace(body)) + } +} + +/// tags API resource. +#[derive(Clone)] +pub struct ThreadsTagsResource { + client: Client, + /// Bound thread scope. + thread: String, +} + +impl ThreadsTagsResource { + /// Remove tags from a thread + pub async fn remove(&self) -> Result { + let mut path = "/api/v1/threads/{thread}/tags".to_owned(); + path = path.replace("{thread}", &crate::encode_path(self.thread.as_str())); + let request = self.client.request(Method::DELETE, &path); + request.send().await + } + /// Blocking variant of [Self::remove]. + #[cfg(feature = "blocking")] + pub fn remove_blocking(&self) -> Result { + crate::blocking::block_on(self.remove()) + } + /// Add tags to a thread + pub async fn create(&self, body: &PostApiV1ThreadsThreadTagsInput) -> Result { + let mut path = "/api/v1/threads/{thread}/tags".to_owned(); + path = path.replace("{thread}", &crate::encode_path(self.thread.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1ThreadsThreadTagsInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Replace a thread's tags + pub async fn replace(&self, body: &PutApiV1ThreadsThreadTagsInput) -> Result { + let mut path = "/api/v1/threads/{thread}/tags".to_owned(); + path = path.replace("{thread}", &crate::encode_path(self.thread.as_str())); + let request = self.client.request(Method::PUT, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::replace]. + #[cfg(feature = "blocking")] + pub fn replace_blocking(&self, body: &PutApiV1ThreadsThreadTagsInput) -> Result { + crate::blocking::block_on(self.replace(body)) + } +} + +/// trajectories API resource. +#[derive(Clone)] +pub struct TrajectoriesResource { + client: Client, +} + +impl TrajectoriesResource { + /// Retrieve a trajectory + pub async fn get(&self, trajectory: &str) -> Result { + let mut path = "/api/v1/trajectories/{trajectory}".to_owned(); + path = path.replace("{trajectory}", &crate::encode_path(trajectory)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, trajectory: &str) -> Result { + crate::blocking::block_on(self.get(trajectory)) + } + /// Retrieve raw trajectory contents + pub async fn contents(&self, trajectory: &str) -> Result { + let mut path = "/api/v1/trajectories/{trajectory}/contents".to_owned(); + path = path.replace("{trajectory}", &crate::encode_path(trajectory)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::contents]. + #[cfg(feature = "blocking")] + pub fn contents_blocking(&self, trajectory: &str) -> Result { + crate::blocking::block_on(self.contents(trajectory)) + } +} + +/// users API resource. +#[derive(Clone)] +pub struct UsersResource { + client: Client, +} + +impl UsersResource { + /// Access the nested tasks resource. + pub fn tasks(&self, user: &str) -> UsersTasksResource { + UsersTasksResource { + client: self.client.clone(), + user: user.to_owned(), + } + } + /// Access the nested threads resource. + pub fn threads(&self, user: &str) -> UsersThreadsResource { + UsersThreadsResource { + client: self.client.clone(), + user: user.to_owned(), + } + } + /// Access the nested tokens resource. + pub fn tokens(&self, user: &str) -> UsersTokensResource { + UsersTokensResource { + client: self.client.clone(), + user: user.to_owned(), + } + } + /// Retrieve the current user + pub async fn me(&self) -> Result { + let path = "/api/v1/users/me".to_owned(); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::me]. + #[cfg(feature = "blocking")] + pub fn me_blocking(&self) -> Result { + crate::blocking::block_on(self.me()) + } + /// Retrieve a user by ID + pub async fn get(&self, user: &str) -> Result { + let mut path = "/api/v1/users/{user}".to_owned(); + path = path.replace("{user}", &crate::encode_path(user)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::get]. + #[cfg(feature = "blocking")] + pub fn get_blocking(&self, user: &str) -> Result { + crate::blocking::block_on(self.get(user)) + } + /// List a user's artifacts + pub async fn artifacts(&self, user: &str) -> Result { + let mut path = "/api/v1/users/{user}/artifacts".to_owned(); + path = path.replace("{user}", &crate::encode_path(user)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::artifacts]. + #[cfg(feature = "blocking")] + pub fn artifacts_blocking(&self, user: &str) -> Result { + crate::blocking::block_on(self.artifacts(user)) + } + /// Create a user invite + pub async fn invites( + &self, + user: &str, + body: &PostApiV1UsersUserInvitesInput, + ) -> Result { + let mut path = "/api/v1/users/{user}/invites".to_owned(); + path = path.replace("{user}", &crate::encode_path(user)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::invites]. + #[cfg(feature = "blocking")] + pub fn invites_blocking( + &self, + user: &str, + body: &PostApiV1UsersUserInvitesInput, + ) -> Result { + crate::blocking::block_on(self.invites(user, body)) + } + /// List organizations for a user + pub async fn orgs(&self, user: &str) -> Result { + let mut path = "/api/v1/users/{user}/orgs".to_owned(); + path = path.replace("{user}", &crate::encode_path(user)); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::orgs]. + #[cfg(feature = "blocking")] + pub fn orgs_blocking(&self, user: &str) -> Result { + crate::blocking::block_on(self.orgs(user)) + } + /// Update the current user's profile + pub async fn profile(&self, user: &str, body: &PutApiV1UsersUserProfileInput) -> Result { + let mut path = "/api/v1/users/{user}/profile".to_owned(); + path = path.replace("{user}", &crate::encode_path(user)); + let request = self.client.request(Method::PUT, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::profile]. + #[cfg(feature = "blocking")] + pub fn profile_blocking( + &self, + user: &str, + body: &PutApiV1UsersUserProfileInput, + ) -> Result { + crate::blocking::block_on(self.profile(user, body)) + } +} + +/// tasks API resource. +#[derive(Clone)] +pub struct UsersTasksResource { + client: Client, + /// Bound user scope. + user: String, +} + +impl UsersTasksResource { + /// List an owner's tasks + pub async fn list( + &self, + params: Option<&GetApiV1UsersUserTasksParams>, + ) -> Result { + let mut path = "/api/v1/users/{user}/tasks".to_owned(); + path = path.replace("{user}", &crate::encode_path(self.user.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1UsersUserTasksParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create a task for an owner + pub async fn create(&self, body: &PostApiV1UsersUserTasksInput) -> Result { + let mut path = "/api/v1/users/{user}/tasks".to_owned(); + path = path.replace("{user}", &crate::encode_path(self.user.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1UsersUserTasksInput) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// List task blocker cycles + pub async fn blocker_cycles( + &self, + params: Option<&GetApiV1UsersUserTasksBlockerCyclesParams>, + ) -> Result { + let mut path = "/api/v1/users/{user}/tasks/blocker_cycles".to_owned(); + path = path.replace("{user}", &crate::encode_path(self.user.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::blocker_cycles]. + #[cfg(feature = "blocking")] + pub fn blocker_cycles_blocking( + &self, + params: Option<&GetApiV1UsersUserTasksBlockerCyclesParams>, + ) -> Result { + crate::blocking::block_on(self.blocker_cycles(params)) + } + /// List an owner's ready tasks + pub async fn ready( + &self, + params: Option<&GetApiV1UsersUserTasksReadyParams>, + ) -> Result { + let mut path = "/api/v1/users/{user}/tasks/ready".to_owned(); + path = path.replace("{user}", &crate::encode_path(self.user.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::ready]. + #[cfg(feature = "blocking")] + pub fn ready_blocking( + &self, + params: Option<&GetApiV1UsersUserTasksReadyParams>, + ) -> Result { + crate::blocking::block_on(self.ready(params)) + } + /// Search an owner's tasks + pub async fn search( + &self, + params: Option<&GetApiV1UsersUserTasksSearchParams>, + ) -> Result { + let mut path = "/api/v1/users/{user}/tasks/search".to_owned(); + path = path.replace("{user}", &crate::encode_path(self.user.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::search]. + #[cfg(feature = "blocking")] + pub fn search_blocking( + &self, + params: Option<&GetApiV1UsersUserTasksSearchParams>, + ) -> Result { + crate::blocking::block_on(self.search(params)) + } +} + +/// threads API resource. +#[derive(Clone)] +pub struct UsersThreadsResource { + client: Client, + /// Bound user scope. + user: String, +} + +impl UsersThreadsResource { + /// List threads for a user + pub async fn list( + &self, + params: Option<&GetApiV1UsersUserThreadsParams>, + ) -> Result { + let mut path = "/api/v1/users/{user}/threads".to_owned(); + path = path.replace("{user}", &crate::encode_path(self.user.as_str())); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1UsersUserThreadsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Create a thread for a user + pub async fn create(&self, body: &PostApiV1UsersUserThreadsInput) -> Result { + let mut path = "/api/v1/users/{user}/threads".to_owned(); + path = path.replace("{user}", &crate::encode_path(self.user.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking(&self, body: &PostApiV1UsersUserThreadsInput) -> Result { + crate::blocking::block_on(self.create(body)) + } +} + +/// tokens API resource. +#[derive(Clone)] +pub struct UsersTokensResource { + client: Client, + /// Bound user scope. + user: String, +} + +impl UsersTokensResource { + /// List personal access tokens + pub async fn list(&self) -> Result { + let mut path = "/api/v1/users/{user}/tokens".to_owned(); + path = path.replace("{user}", &crate::encode_path(self.user.as_str())); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking(&self) -> Result { + crate::blocking::block_on(self.list()) + } + /// Create a personal access token + pub async fn create(&self, body: &PostApiV1UsersUserTokensInput) -> Result { + let mut path = "/api/v1/users/{user}/tokens".to_owned(); + path = path.replace("{user}", &crate::encode_path(self.user.as_str())); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking( + &self, + body: &PostApiV1UsersUserTokensInput, + ) -> Result { + crate::blocking::block_on(self.create(body)) + } + /// Revoke a personal access token + pub async fn delete(&self, token: &str) -> Result { + let mut path = "/api/v1/users/{user}/tokens/{token}".to_owned(); + path = path.replace("{user}", &crate::encode_path(self.user.as_str())); + path = path.replace("{token}", &crate::encode_path(token)); + let request = self.client.request(Method::DELETE, &path); + request.send().await + } + /// Blocking variant of [Self::delete]. + #[cfg(feature = "blocking")] + pub fn delete_blocking(&self, token: &str) -> Result { + crate::blocking::block_on(self.delete(token)) + } +} + +/// work_items API resource. +#[derive(Clone)] +pub struct WorkItemsResource { + client: Client, +} + +impl WorkItemsResource { + /// List active workflow work available to the viewer + pub async fn list( + &self, + params: Option<&GetApiV1WorkItemsParams>, + ) -> Result { + let path = "/api/v1/work_items".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = match params { + Some(value) => request.query(value)?, + None => request, + }; + request.send().await + } + /// Blocking variant of [Self::list]. + #[cfg(feature = "blocking")] + pub fn list_blocking( + &self, + params: Option<&GetApiV1WorkItemsParams>, + ) -> Result { + crate::blocking::block_on(self.list(params)) + } + /// Fail workflow work and route its durable execution + pub async fn fail( + &self, + work_item: &str, + body: &PostApiV1WorkItemsWorkItemFailInput, + ) -> Result<()> { + let mut path = "/api/v1/work_items/{work_item}/fail".to_owned(); + path = path.replace("{work_item}", &crate::encode_path(work_item)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send_empty().await + } + /// Blocking variant of [Self::fail]. + #[cfg(feature = "blocking")] + pub fn fail_blocking( + &self, + work_item: &str, + body: &PostApiV1WorkItemsWorkItemFailInput, + ) -> Result<()> { + crate::blocking::block_on(self.fail(work_item, body)) + } + /// Extend a workflow work item lease + pub async fn heartbeat( + &self, + work_item: &str, + body: &PostApiV1WorkItemsWorkItemHeartbeatInput, + ) -> Result<()> { + let mut path = "/api/v1/work_items/{work_item}/heartbeat".to_owned(); + path = path.replace("{work_item}", &crate::encode_path(work_item)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send_empty().await + } + /// Blocking variant of [Self::heartbeat]. + #[cfg(feature = "blocking")] + pub fn heartbeat_blocking( + &self, + work_item: &str, + body: &PostApiV1WorkItemsWorkItemHeartbeatInput, + ) -> Result<()> { + crate::blocking::block_on(self.heartbeat(work_item, body)) + } + /// Mark claimed workflow work as running + pub async fn start( + &self, + work_item: &str, + body: &PostApiV1WorkItemsWorkItemStartInput, + ) -> Result<()> { + let mut path = "/api/v1/work_items/{work_item}/start".to_owned(); + path = path.replace("{work_item}", &crate::encode_path(work_item)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send_empty().await + } + /// Blocking variant of [Self::start]. + #[cfg(feature = "blocking")] + pub fn start_blocking( + &self, + work_item: &str, + body: &PostApiV1WorkItemsWorkItemStartInput, + ) -> Result<()> { + crate::blocking::block_on(self.start(work_item, body)) + } + /// Submit workflow work output and wake its durable execution + pub async fn submit( + &self, + work_item: &str, + body: &PostApiV1WorkItemsWorkItemSubmitInput, + ) -> Result<()> { + let mut path = "/api/v1/work_items/{work_item}/submit".to_owned(); + path = path.replace("{work_item}", &crate::encode_path(work_item)); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send_empty().await + } + /// Blocking variant of [Self::submit]. + #[cfg(feature = "blocking")] + pub fn submit_blocking( + &self, + work_item: &str, + body: &PostApiV1WorkItemsWorkItemSubmitInput, + ) -> Result<()> { + crate::blocking::block_on(self.submit(work_item, body)) + } +} + +/// ai API resource. +#[derive(Clone)] +pub struct AiResource { + client: Client, +} + +impl AiResource { + /// Access the nested chat resource. + pub fn chat(&self) -> AiChatResource { + AiChatResource { + client: self.client.clone(), + } + } + /// Access the nested embedding resource. + pub fn embedding(&self) -> AiEmbeddingResource { + AiEmbeddingResource { + client: self.client.clone(), + } + } + /// Access the nested image resource. + pub fn image(&self) -> AiImageResource { + AiImageResource { + client: self.client.clone(), + } + } +} + +/// chat API resource. +#[derive(Clone)] +pub struct AiChatResource { + client: Client, +} + +impl AiChatResource { + /// Access the nested completions resource. + pub fn completions(&self) -> AiChatCompletionsResource { + AiChatCompletionsResource { + client: self.client.clone(), + } + } + /// List available AI models + pub async fn models(&self) -> Result { + let path = "/api/v1/ai/chat/models".to_owned(); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::models]. + #[cfg(feature = "blocking")] + pub fn models_blocking(&self) -> Result { + crate::blocking::block_on(self.models()) + } +} + +/// completions API resource. +#[derive(Clone)] +pub struct AiChatCompletionsResource { + client: Client, +} + +impl AiChatCompletionsResource { + /// Access the nested stream resource. + pub fn stream(&self) -> AiChatCompletionsStreamResource { + AiChatCompletionsStreamResource { + client: self.client.clone(), + } + } + /// Create a chat completion + pub async fn create( + &self, + body: &PostApiV1AiChatCompletionsInput, + ) -> Result { + let path = "/api/v1/ai/chat/completions".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::create]. + #[cfg(feature = "blocking")] + pub fn create_blocking( + &self, + body: &PostApiV1AiChatCompletionsInput, + ) -> Result { + crate::blocking::block_on(self.create(body)) + } +} + +/// stream API resource. +#[derive(Clone)] +pub struct AiChatCompletionsStreamResource { + client: Client, +} + +impl AiChatCompletionsStreamResource { + /// Stream a chat completion + pub async fn create( + &self, + body: &PostApiV1AiChatCompletionsStreamInput, + ) -> Result> { + let path = "/api/v1/ai/chat/completions/stream".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.stream().await + } +} + +/// embedding API resource. +#[derive(Clone)] +pub struct AiEmbeddingResource { + client: Client, +} + +impl AiEmbeddingResource { + /// Compare the embedding similarity of two texts + pub async fn similarity_comparison( + &self, + body: &PostApiV1AiEmbeddingSimilarityComparisonInput, + ) -> Result { + let path = "/api/v1/ai/embedding/similarity_comparison".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::similarity_comparison]. + #[cfg(feature = "blocking")] + pub fn similarity_comparison_blocking( + &self, + body: &PostApiV1AiEmbeddingSimilarityComparisonInput, + ) -> Result { + crate::blocking::block_on(self.similarity_comparison(body)) + } +} + +/// image API resource. +#[derive(Clone)] +pub struct AiImageResource { + client: Client, +} + +impl AiImageResource { + /// Edit an image with a text prompt + pub async fn edits(&self, body: &PostApiV1AiImageEditsInput) -> Result { + let path = "/api/v1/ai/image/edits".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::edits]. + #[cfg(feature = "blocking")] + pub fn edits_blocking(&self, body: &PostApiV1AiImageEditsInput) -> Result { + crate::blocking::block_on(self.edits(body)) + } + /// Generate an image from a text prompt + pub async fn generations( + &self, + body: &PostApiV1AiImageGenerationsInput, + ) -> Result { + let path = "/api/v1/ai/image/generations".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::generations]. + #[cfg(feature = "blocking")] + pub fn generations_blocking( + &self, + body: &PostApiV1AiImageGenerationsInput, + ) -> Result { + crate::blocking::block_on(self.generations(body)) + } + /// List available image generation models + pub async fn models(&self) -> Result { + let path = "/api/v1/ai/image/models".to_owned(); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::models]. + #[cfg(feature = "blocking")] + pub fn models_blocking(&self) -> Result { + crate::blocking::block_on(self.models()) + } +} + +/// oauth API resource. +#[derive(Clone)] +pub struct OauthResource { + client: Client, +} + +impl OauthResource { + /// Access the nested device resource. + pub fn device(&self) -> OauthDeviceResource { + OauthDeviceResource { + client: self.client.clone(), + } + } + /// List available OAuth scopes + pub async fn scopes(&self) -> Result { + let path = "/oauth/scopes".to_owned(); + let request = self.client.request(Method::GET, &path); + request.send().await + } + /// Blocking variant of [Self::scopes]. + #[cfg(feature = "blocking")] + pub fn scopes_blocking(&self) -> Result { + crate::blocking::block_on(self.scopes()) + } + /// Exchange a grant for OAuth tokens + pub async fn token(&self, body: &PostOauthTokenInput) -> Result { + let path = "/oauth/token".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::token]. + #[cfg(feature = "blocking")] + pub fn token_blocking(&self, body: &PostOauthTokenInput) -> Result { + crate::blocking::block_on(self.token(body)) + } +} + +/// device API resource. +#[derive(Clone)] +pub struct OauthDeviceResource { + client: Client, +} + +impl OauthDeviceResource { + /// Approve a device authorization request + pub async fn approve( + &self, + body: &PostOauthDeviceApproveInput, + ) -> Result { + let path = "/oauth/device/approve".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::approve]. + #[cfg(feature = "blocking")] + pub fn approve_blocking( + &self, + body: &PostOauthDeviceApproveInput, + ) -> Result { + crate::blocking::block_on(self.approve(body)) + } + /// Inspect a pending device authorization + pub async fn authorization( + &self, + params: &GetOauthDeviceAuthorizationParams, + ) -> Result { + let path = "/oauth/device/authorization".to_owned(); + let request = self.client.request(Method::GET, &path); + let request = request.query(params)?; + request.send().await + } + /// Blocking variant of [Self::authorization]. + #[cfg(feature = "blocking")] + pub fn authorization_blocking( + &self, + params: &GetOauthDeviceAuthorizationParams, + ) -> Result { + crate::blocking::block_on(self.authorization(params)) + } + /// Initiate a device authorization request + pub async fn authorize( + &self, + body: &PostOauthDeviceAuthorizeInput, + ) -> Result { + let path = "/oauth/device/authorize".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::authorize]. + #[cfg(feature = "blocking")] + pub fn authorize_blocking( + &self, + body: &PostOauthDeviceAuthorizeInput, + ) -> Result { + crate::blocking::block_on(self.authorize(body)) + } + /// Deny a device authorization request + pub async fn deny( + &self, + body: &PostOauthDeviceDenyInput, + ) -> Result { + let path = "/oauth/device/deny".to_owned(); + let request = self.client.request(Method::POST, &path); + let request = request.json(body)?; + request.send().await + } + /// Blocking variant of [Self::deny]. + #[cfg(feature = "blocking")] + pub fn deny_blocking( + &self, + body: &PostOauthDeviceDenyInput, + ) -> Result { + crate::blocking::block_on(self.deny(body)) + } +} diff --git a/src/http.rs b/src/http.rs new file mode 100644 index 0000000..9e1a614 --- /dev/null +++ b/src/http.rs @@ -0,0 +1,254 @@ +use futures_util::StreamExt; +use reqwest::header::{HeaderName, HeaderValue}; +use reqwest_eventsource::{Event, RequestBuilderExt}; +use serde::Serialize; +use serde::de::DeserializeOwned; +use serde_json::{Value, json}; + +use crate::sse::{SseDecode, SseStream}; +use crate::{ApiError, Client, Error, Result}; + +/// Raw bytes returned by download/export endpoints. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct RawResponse { + /// Body bytes. + pub bytes: Vec, + /// Response MIME type, when supplied. + pub content_type: Option, +} + +/// Fluent request assembled by generated resource methods. +pub struct RequestBuilder { + client: Client, + method: reqwest::Method, + path: String, + query: Option, + body: Option, +} + +impl RequestBuilder { + pub(crate) fn new(client: Client, method: reqwest::Method, path: &str) -> Self { + Self { + client, + method, + path: path.to_owned(), + query: None, + body: None, + } + } + + /// Serialize query parameters according to `application/x-www-form-urlencoded` rules. + pub fn query(mut self, value: &impl Serialize) -> Result { + self.query = Some(serde_urlencoded::to_string(value)?); + Ok(self) + } + + /// Serialize a JSON request body. + pub fn json(mut self, value: &impl Serialize) -> Result { + self.body = Some(serde_json::to_value(value)?); + Ok(self) + } + + /// Send and decode a JSON response. + pub async fn send(self) -> Result { + let response = self.execute().await?; + let status = response.status(); + let bytes = response.bytes().await?; + if bytes.is_empty() { + return Err(Error::Api(ApiError { + status: status.as_u16(), + code: Some("empty_response".into()), + message: "server returned no body for an operation that promises one".into(), + body: Value::Null, + })); + } + Ok(serde_json::from_slice(&bytes)?) + } + + /// Send an operation whose contract has no response body. + pub async fn send_empty(self) -> Result<()> { + let _ = self.execute().await?; + Ok(()) + } + + /// Send and retain raw response bytes. + pub async fn send_raw(self) -> Result { + let response = self.execute().await?; + let content_type = response + .headers() + .get(reqwest::header::CONTENT_TYPE) + .and_then(|value| value.to_str().ok()) + .map(str::to_owned); + Ok(RawResponse { + bytes: response.bytes().await?.to_vec(), + content_type, + }) + } + + /// Open and decode an SSE response as a typed stream. + pub async fn stream(self) -> Result> { + let generation = self.client.0.session.read().await.generation; + match self.open_stream().await { + Err(Error::Api(error)) if error.status == 401 => { + if !self.client.refresh_if_generation(generation).await? { + return Err(error.into()); + } + self.open_stream().await + } + result => result, + } + } + + async fn open_stream(&self) -> Result> { + let mut source = self + .build() + .await? + .eventsource() + .map_err(|error| Error::Sse(error.to_string()))?; + match source.next().await { + Some(Ok(Event::Open)) => Ok(SseStream::from_source(source)), + Some(Ok(Event::Message(_))) => Err(Error::Sse( + "SSE message arrived before the open event".into(), + )), + Some(Err(reqwest_eventsource::Error::InvalidStatusCode(_, response))) => { + match checked(response).await { + Err(error) => Err(error), + Ok(_) => Err(Error::Sse("SSE endpoint rejected its status".into())), + } + } + Some(Err(error)) => Err(Error::Sse(error.to_string())), + None => Err(Error::Closed), + } + } + + async fn execute(self) -> Result { + let generation = self.client.0.session.read().await.generation; + let response = self.build().await?.send().await?; + if response.status() != reqwest::StatusCode::UNAUTHORIZED { + return checked(response).await; + } + if !self.client.refresh_if_generation(generation).await? { + return checked(response).await; + } + checked(self.build().await?.send().await?).await + } + + async fn build(&self) -> Result { + let mut url = format!("{}{}", self.client.0.base_url, self.path); + if let Some(query) = &self.query { + if !query.is_empty() { + url.push('?'); + url.push_str(query); + } + } + let mut request = self.client.0.http.request(self.method.clone(), url); + for (name, value) in &self.client.0.headers { + request = request.header( + HeaderName::try_from(name.as_str()) + .map_err(|error| Error::Configuration(error.to_string()))?, + HeaderValue::try_from(value.as_str()) + .map_err(|error| Error::Configuration(error.to_string()))?, + ); + } + if let Some(token) = self.client.0.session.read().await.access_token.clone() { + request = request.bearer_auth(token); + } + if let Some(body) = &self.body { + request = request.json(body); + } + Ok(request) + } +} + +impl Client { + pub(crate) async fn refresh_if_generation(&self, observed: u64) -> Result { + let _gate = self.0.refresh_gate.lock().await; + let snapshot = self.0.session.read().await.clone(); + if snapshot.generation != observed { + return Ok(true); + } + let (Some(refresh_token), Some(refresh_path)) = + (snapshot.refresh_token, snapshot.refresh_path) + else { + return Ok(false); + }; + + // This refresh-only request deliberately bypasses RequestBuilder so a + // 401 cannot recursively enter refresh. Refresh tokens are single-use. + let url = format!("{}{}", self.0.base_url, refresh_path); + let mut request = self + .0 + .http + .post(url) + .json(&json!({ "refresh_token": refresh_token })); + for (name, value) in &self.0.headers { + request = request.header(name, value); + } + let response = checked(request.send().await?).await?; + let body: Value = response.json().await?; + let access = body + .get("access_token") + .and_then(Value::as_str) + .ok_or_else(|| Error::Configuration("refresh response omitted access_token".into()))?; + let refresh = body + .get("refresh_token") + .and_then(Value::as_str) + .map(str::to_owned); + let mut session = self.0.session.write().await; + session.access_token = Some(access.to_owned()); + if refresh.is_some() { + session.refresh_token = refresh; + } + session.generation = session.generation.wrapping_add(1); + let persisted = crate::AppSession { + access_token: access.to_owned(), + refresh_token: session.refresh_token.clone(), + access_token_expires_at: session.access_token_expires_at, + user: session.user.clone(), + }; + drop(session); + if let Some(store) = &self.0.session_store { + // The fresh in-memory bearer must remain usable if secure storage + // has a transient failure; the next successful rotation retries. + let _ = store.save(&persisted).await; + } + Ok(true) + } +} + +async fn checked(response: reqwest::Response) -> Result { + if response.status().is_success() { + return Ok(response); + } + let status = response.status().as_u16(); + let bytes = response.bytes().await?; + let body: Value = serde_json::from_slice(&bytes) + .unwrap_or_else(|_| Value::String(String::from_utf8_lossy(&bytes).into_owned())); + let code = body + .get("code") + .and_then(Value::as_str) + .map(str::to_owned) + .or_else(|| { + body.get("error") + .and_then(|error| error.get("code")) + .and_then(Value::as_str) + .map(str::to_owned) + }); + let message = body + .get("message") + .and_then(Value::as_str) + .or_else(|| { + body.get("error") + .and_then(|error| error.get("message")) + .and_then(Value::as_str) + }) + .unwrap_or("request failed") + .to_owned(); + Err(ApiError { + status, + code, + message, + body, + } + .into()) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..c04f329 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,30 @@ +//! Official, generated-first Rust SDK for ArchAstro. +//! +//! [`Client`] is asynchronous and runtime-agnostic at its public boundary. +//! Enable the default `blocking` feature for `_blocking` resource methods. + +mod channel; +mod client; +mod error; +mod http; +mod session; +pub mod sse; + +#[cfg(feature = "blocking")] +pub mod blocking; +/// Generated API models, resources, authentication, and channel facades. +pub mod generated; + +pub use channel::{ + Channel, ChannelEventStream, ChannelState, Socket, SocketBuilder, SocketEvent, + SocketEventStream, +}; +pub use client::{Client, ClientBuilder}; +pub use error::{ApiError, ChannelError, Error, Result}; +pub use http::{RawResponse, RequestBuilder}; +pub use session::{AppSession, SessionStore}; + +/// Percent-encode one path segment without changing path separators. +pub fn encode_path(value: &str) -> String { + url::form_urlencoded::byte_serialize(value.as_bytes()).collect() +} diff --git a/src/session.rs b/src/session.rs new file mode 100644 index 0000000..d1cd3ba --- /dev/null +++ b/src/session.rs @@ -0,0 +1,36 @@ +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +/// Durable app-user session suitable for secure storage. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AppSession { + /// Bearer access token. + pub access_token: String, + /// Single-use refresh token used to renew the session. + pub refresh_token: Option, + /// Access-token expiry as Unix milliseconds, when known. + pub access_token_expires_at: Option, + /// Authenticated user snapshot, when supplied by the login flow. + pub user: Option, +} + +/// Async durable storage used by app clients. +/// +/// Mobile applications commonly implement this with a secure keychain; +/// servers may use an encrypted database or another application-owned store. +#[async_trait::async_trait] +pub trait SessionStore: Send + Sync { + /// Load a previously persisted session. + async fn load( + &self, + ) -> std::result::Result, Box>; + + /// Persist the current session, including rotated refresh credentials. + async fn save( + &self, + session: &AppSession, + ) -> std::result::Result<(), Box>; + + /// Remove any persisted session. + async fn clear(&self) -> std::result::Result<(), Box>; +} diff --git a/src/sse.rs b/src/sse.rs new file mode 100644 index 0000000..250753b --- /dev/null +++ b/src/sse.rs @@ -0,0 +1,72 @@ +//! Typed Server-Sent Events support. + +use std::marker::PhantomData; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use futures_core::Stream; +use reqwest_eventsource::{Event, EventSource}; + +use crate::{Error, Result}; + +/// Implemented by generated endpoint-specific SSE enums. +pub trait SseDecode: Sized + Send + 'static { + /// Decode one wire event and JSON data payload. + fn decode(event: &str, data: &str) -> Result; +} + +/// One typed SSE message. +#[derive(Debug, Clone, PartialEq)] +pub struct SseEvent { + /// Event name. + pub event: String, + /// Last-event ID, when supplied. + pub id: String, + /// Typed payload. + pub data: T, +} + +/// Auto-reconnecting typed SSE stream. +pub struct SseStream { + source: EventSource, + marker: PhantomData, +} + +impl SseStream { + pub(crate) fn from_source(source: EventSource) -> Self { + Self { + source, + marker: PhantomData, + } + } + + /// Stop reconnection and close the stream. + pub fn close(&mut self) { + self.source.close(); + } +} + +impl Stream for SseStream { + type Item = Result>; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + loop { + match Pin::new(&mut self.source).poll_next(cx) { + Poll::Ready(Some(Ok(Event::Open))) => continue, + Poll::Ready(Some(Ok(Event::Message(message)))) => { + let decoded = T::decode(&message.event, &message.data).map(|data| SseEvent { + event: message.event, + id: message.id, + data, + }); + return Poll::Ready(Some(decoded)); + } + Poll::Ready(Some(Err(error))) => { + return Poll::Ready(Some(Err(Error::Sse(error.to_string())))); + } + Poll::Ready(None) => return Poll::Ready(None), + Poll::Pending => return Poll::Pending, + } + } + } +} diff --git a/tests/channel_runtime_contract.rs b/tests/channel_runtime_contract.rs new file mode 100644 index 0000000..c1aadf6 --- /dev/null +++ b/tests/channel_runtime_contract.rs @@ -0,0 +1,141 @@ +//! Fault-injection contracts for the hand-maintained Phoenix runtime. + +mod support; + +use std::time::Duration; + +use archastro::generated::{ApiObjectChannel, ApiObjectChannelJoinByIdParams}; +use archastro::{ChannelState, Error, SocketBuilder, SocketEvent}; +use futures_util::StreamExt; +use serde_json::json; + +fn join_params() -> ApiObjectChannelJoinByIdParams { + serde_json::from_value(json!({})).expect("valid join params") +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn join_rejection_preserves_the_server_payload() { + support::mark_all_used(); + let harness = support::harness().await; + harness + .register_scenario(&json!({ + "topic": "api:object:test-id", + "onJoin": [{ "type": "replyError", "payload": { "reason": "denied" } }] + })) + .await; + let socket = harness.socket().await; + let error = match ApiObjectChannel::join_by_id(&socket, "test-id", &join_params()).await { + Ok(_) => panic!("join must fail"), + Err(error) => error, + }; + match error { + Error::Channel(error) => assert_eq!(error.payload, Some(json!({ "reason": "denied" }))), + other => panic!("expected channel error, got {other:?}"), + } +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn push_rejection_and_timeout_are_typed_errors() { + let harness = support::harness().await; + harness + .register_scenario(&json!({ + "topic": "api:object:test-id", + "onJoin": [{ "type": "autoReply" }], + "onMessage": { + "save": [{ "type": "replyError", "payload": { "reason": "conflict" } }], + "presence_update": [{ "type": "replyTimeout" }] + } + })) + .await; + let socket = SocketBuilder::new(harness.ws_url()) + .timeout(Duration::from_millis(50)) + .connect() + .await + .expect("connect socket"); + let channel = ApiObjectChannel::join_by_id(&socket, "test-id", &join_params()) + .await + .expect("join channel"); + + assert!(matches!(channel.save().await, Err(Error::Channel(_)))); + let timeout = channel + .channel + .push("presence_update", json!({ "presence": {} })) + .await; + assert!(matches!(timeout, Err(Error::Timeout))); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn disconnect_reconnects_rejoins_and_flushes_buffered_pushes() { + let harness = support::harness().await; + harness + .register_scenario(&json!({ + "topic": "api:object:test-id", + "onJoin": [{ "type": "autoReply" }], + "onMessage": { + "update_fields": [{ "type": "disconnect" }], + "save": [{ "type": "autoReply" }] + } + })) + .await; + let socket = SocketBuilder::new(harness.ws_url()) + .reconnect_backoff([Duration::from_millis(150)]) + .connect() + .await + .expect("connect socket"); + let mut socket_events = socket.events(); + let channel = ApiObjectChannel::join_by_id(&socket, "test-id", &join_params()) + .await + .expect("join channel"); + + let disconnect = channel + .channel + .push("update_fields", json!({ "fields": {} })) + .await; + assert!(matches!(disconnect, Err(Error::Closed))); + assert!(matches!( + socket_events.next().await, + Some(SocketEvent::Close { .. }) + )); + + let save = channel.save(); + tokio::pin!(save); + assert!( + tokio::time::timeout(Duration::from_millis(50), &mut save) + .await + .is_err() + ); + assert_eq!(socket_events.next().await, Some(SocketEvent::Open)); + save.await.expect("buffered push flushes after rejoin"); + assert_eq!(channel.channel.state().await, ChannelState::Joined); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn acknowledged_heartbeats_keep_the_channel_usable() { + let harness = support::harness().await; + harness + .register_scenario(&json!({ + "topic": "api:object:test-id", + "onJoin": [{ "type": "autoReply" }], + "onMessage": { "save": [{ "type": "autoReply" }] } + })) + .await; + let socket = SocketBuilder::new(harness.ws_url()) + .heartbeat(Duration::from_millis(20)) + .connect() + .await + .expect("connect socket"); + let channel = ApiObjectChannel::join_by_id(&socket, "test-id", &join_params()) + .await + .expect("join channel"); + tokio::time::sleep(Duration::from_millis(75)).await; + channel.save().await.expect("push after heartbeats"); + assert!(socket.is_connected()); +} diff --git a/tests/generated_channel_contract.rs b/tests/generated_channel_contract.rs new file mode 100644 index 0000000..0ed21e6 --- /dev/null +++ b/tests/generated_channel_contract.rs @@ -0,0 +1,449 @@ +// Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License. +// This file is auto-generated by @archastro/sdk-generator. Do not edit. +// Content hash: f3d758c6927d + +//! Generated Phoenix channel contract tests. +mod support; +use archastro::generated::*; +use futures_util::StreamExt; + +#[test] +fn generated_support_is_linked() { + support::mark_all_used(); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_activity_feed_channel_join_agent_join() { + let harness = support::harness().await; + let topic = "api:activity_feed:agent:test-id"; + harness.register_channel(topic, &[], &[]).await; + let socket = harness.socket().await; + let channel = ApiActivityFeedChannel::join_agent(&socket, "test-id") + .await + .expect("join channel"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_activity_feed_channel_join_org_join() { + let harness = support::harness().await; + let topic = "api:activity_feed:org:test-id"; + harness.register_channel(topic, &[], &[]).await; + let socket = harness.socket().await; + let channel = ApiActivityFeedChannel::join_org(&socket, "test-id") + .await + .expect("join channel"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_activity_feed_channel_messages_and_pushes() { + let harness = support::harness().await; + let topic = "api:activity_feed:agent:test-id"; + harness + .register_channel(topic, &["list_entries"], &["new_entry"]) + .await; + let socket = harness.socket().await; + let channel = ApiActivityFeedChannel::join_agent(&socket, "test-id") + .await + .expect("join channel"); + let message_0: ApiActivityFeedChannelListEntriesInput = + serde_json::from_str(r#"{}"#).expect("valid message input"); + channel + .list_entries(&message_0) + .await + .expect("channel push"); + let mut push_0 = channel.subscribe_new_entry(); + push_0 + .next() + .await + .expect("server push") + .expect("decode server push"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_chat_channel_join_team_thread_join() { + let harness = support::harness().await; + let topic = "api:chat:team:test-id:thread:test-id"; + let join_params: ApiChatChannelJoinTeamThreadParams = + serde_json::from_str(r#"{}"#).expect("valid join params"); + harness.register_channel(topic, &[], &[]).await; + let socket = harness.socket().await; + let channel = ApiChatChannel::join_team_thread(&socket, "test-id", "test-id", &join_params) + .await + .expect("join channel"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_chat_channel_join_team_keyed_join() { + let harness = support::harness().await; + let topic = "api:chat:team:test-id:key:test-key"; + let join_params: ApiChatChannelJoinTeamKeyedParams = + serde_json::from_str(r#"{}"#).expect("valid join params"); + harness.register_channel(topic, &[], &[]).await; + let socket = harness.socket().await; + let channel = ApiChatChannel::join_team_keyed(&socket, "test-id", "test-key", &join_params) + .await + .expect("join channel"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_chat_channel_join_team_transient_join() { + let harness = support::harness().await; + let topic = "api:chat:team:test-id:transient:test-key"; + let join_params: ApiChatChannelJoinTeamTransientParams = + serde_json::from_str(r#"{}"#).expect("valid join params"); + harness.register_channel(topic, &[], &[]).await; + let socket = harness.socket().await; + let channel = ApiChatChannel::join_team_transient(&socket, "test-id", "test-key", &join_params) + .await + .expect("join channel"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_chat_channel_join_user_thread_join() { + let harness = support::harness().await; + let topic = "api:chat:user:thread:test-id"; + let join_params: ApiChatChannelJoinUserThreadParams = + serde_json::from_str(r#"{}"#).expect("valid join params"); + harness.register_channel(topic, &[], &[]).await; + let socket = harness.socket().await; + let channel = ApiChatChannel::join_user_thread(&socket, "test-id", &join_params) + .await + .expect("join channel"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_chat_channel_join_user_keyed_join() { + let harness = support::harness().await; + let topic = "api:chat:user:key:test-key"; + let join_params: ApiChatChannelJoinUserKeyedParams = + serde_json::from_str(r#"{}"#).expect("valid join params"); + harness.register_channel(topic, &[], &[]).await; + let socket = harness.socket().await; + let channel = ApiChatChannel::join_user_keyed(&socket, "test-key", &join_params) + .await + .expect("join channel"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_chat_channel_join_user_transient_join() { + let harness = support::harness().await; + let topic = "api:chat:user:transient:test-key"; + let join_params: ApiChatChannelJoinUserTransientParams = + serde_json::from_str(r#"{}"#).expect("valid join params"); + harness.register_channel(topic, &[], &[]).await; + let socket = harness.socket().await; + let channel = ApiChatChannel::join_user_transient(&socket, "test-key", &join_params) + .await + .expect("join channel"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_chat_channel_messages_and_pushes() { + let harness = support::harness().await; + let topic = "api:chat:team:test-id:thread:test-id"; + let join_params: ApiChatChannelJoinTeamThreadParams = + serde_json::from_str(r#"{}"#).expect("valid join params"); + harness + .register_channel( + topic, + &[ + "api:chat:fork_thread", + "api:chat:mark_thread_read", + "api:chat:list_messages", + "api:chat:load_more_messages", + "api:chat:post_message", + "api:chat:post_simple_message", + "api:chat:edit_message", + "api:chat:delete_message", + "api:chat:add_reaction", + "api:chat:remove_reaction", + "api:chat:typing", + ], + &[ + "message_added", + "message_updated", + "thread_event", + "system_event", + "typing", + ], + ) + .await; + let socket = harness.socket().await; + let channel = ApiChatChannel::join_team_thread(&socket, "test-id", "test-id", &join_params) + .await + .expect("join channel"); + let message_0: ApiChatChannelApiChatForkThreadInput = + serde_json::from_str(r#"{"message_id":"test-id"}"#).expect("valid message input"); + channel + .api_chat_fork_thread(&message_0) + .await + .expect("channel push"); + let message_1: ApiChatChannelApiChatMarkThreadReadInput = + serde_json::from_str(r#"{"message_id":"test-id"}"#).expect("valid message input"); + channel + .api_chat_mark_thread_read(&message_1) + .await + .expect("channel push"); + channel + .api_chat_list_messages() + .await + .expect("channel push"); + let message_3: ApiChatChannelApiChatLoadMoreMessagesInput = + serde_json::from_str(r#"{}"#).expect("valid message input"); + channel + .api_chat_load_more_messages(&message_3) + .await + .expect("channel push"); + let message_4: ApiChatChannelApiChatPostMessageInput = + serde_json::from_str(r#"{"content":"test-value"}"#).expect("valid message input"); + channel + .api_chat_post_message(&message_4) + .await + .expect("channel push"); + let message_5: ApiChatChannelApiChatPostSimpleMessageInput = + serde_json::from_str(r#"{}"#).expect("valid message input"); + channel + .api_chat_post_simple_message(&message_5) + .await + .expect("channel push"); + let message_6: ApiChatChannelApiChatEditMessageInput = + serde_json::from_str(r#"{"content":"test-value","message_id":"test-id"}"#) + .expect("valid message input"); + channel + .api_chat_edit_message(&message_6) + .await + .expect("channel push"); + let message_7: ApiChatChannelApiChatDeleteMessageInput = + serde_json::from_str(r#"{"message_id":"test-id"}"#).expect("valid message input"); + channel + .api_chat_delete_message(&message_7) + .await + .expect("channel push"); + let message_8: ApiChatChannelApiChatAddReactionInput = + serde_json::from_str(r#"{"emoji":"test-value","message_id":"test-id"}"#) + .expect("valid message input"); + channel + .api_chat_add_reaction(&message_8) + .await + .expect("channel push"); + let message_9: ApiChatChannelApiChatRemoveReactionInput = + serde_json::from_str(r#"{"emoji":"test-value","message_id":"test-id"}"#) + .expect("valid message input"); + channel + .api_chat_remove_reaction(&message_9) + .await + .expect("channel push"); + let message_10: ApiChatChannelApiChatTypingInput = + serde_json::from_str(r#"{"is_typing":true}"#).expect("valid message input"); + channel + .api_chat_typing(&message_10) + .await + .expect("channel push"); + let mut push_0 = channel.subscribe_message_added(); + push_0 + .next() + .await + .expect("server push") + .expect("decode server push"); + let mut push_1 = channel.subscribe_message_updated(); + push_1 + .next() + .await + .expect("server push") + .expect("decode server push"); + let mut push_2 = channel.subscribe_thread_event(); + push_2 + .next() + .await + .expect("server push") + .expect("decode server push"); + let mut push_3 = channel.subscribe_system_event(); + push_3 + .next() + .await + .expect("server push") + .expect("decode server push"); + let mut push_4 = channel.subscribe_typing(); + push_4 + .next() + .await + .expect("server push") + .expect("decode server push"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_object_channel_join_by_id_join() { + let harness = support::harness().await; + let topic = "api:object:test-id"; + let join_params: ApiObjectChannelJoinByIdParams = + serde_json::from_str(r#"{}"#).expect("valid join params"); + harness.register_channel(topic, &[], &[]).await; + let socket = harness.socket().await; + let channel = ApiObjectChannel::join_by_id(&socket, "test-id", &join_params) + .await + .expect("join channel"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_object_channel_join_by_row_key_join() { + let harness = support::harness().await; + let topic = "api:object:test-value:test-key"; + let join_params: ApiObjectChannelJoinByRowKeyParams = + serde_json::from_str(r#"{}"#).expect("valid join params"); + harness.register_channel(topic, &[], &[]).await; + let socket = harness.socket().await; + let channel = + ApiObjectChannel::join_by_row_key(&socket, "test-value", "test-key", &join_params) + .await + .expect("join channel"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_object_channel_messages_and_pushes() { + let harness = support::harness().await; + let topic = "api:object:test-id"; + let join_params: ApiObjectChannelJoinByIdParams = + serde_json::from_str(r#"{}"#).expect("valid join params"); + harness + .register_channel( + topic, + &["update_fields", "save", "presence_update"], + &[ + "object_updated", + "object_created", + "object_deleted", + "presence_updated", + "presence_left", + "access_revoked", + ], + ) + .await; + let socket = harness.socket().await; + let channel = ApiObjectChannel::join_by_id(&socket, "test-id", &join_params) + .await + .expect("join channel"); + let message_0: ApiObjectChannelUpdateFieldsInput = + serde_json::from_str(r#"{"fields":{}}"#).expect("valid message input"); + channel + .update_fields(&message_0) + .await + .expect("channel push"); + channel.save().await.expect("channel push"); + let message_2: ApiObjectChannelPresenceUpdateInput = + serde_json::from_str(r#"{"presence":{}}"#).expect("valid message input"); + channel + .presence_update(&message_2) + .await + .expect("channel push"); + let mut push_0 = channel.subscribe_object_updated(); + push_0 + .next() + .await + .expect("server push") + .expect("decode server push"); + let mut push_1 = channel.subscribe_object_created(); + push_1 + .next() + .await + .expect("server push") + .expect("decode server push"); + let mut push_2 = channel.subscribe_object_deleted(); + push_2 + .next() + .await + .expect("server push") + .expect("decode server push"); + let mut push_3 = channel.subscribe_presence_updated(); + push_3 + .next() + .await + .expect("server push") + .expect("decode server push"); + let mut push_4 = channel.subscribe_presence_left(); + push_4 + .next() + .await + .expect("server push") + .expect("decode server push"); + let mut push_5 = channel.subscribe_access_revoked(); + push_5 + .next() + .await + .expect("server push") + .expect("decode server push"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_tasks_channel_join_thread_join() { + let harness = support::harness().await; + let topic = "api:tasks:thread:test-id"; + harness.register_channel(topic, &[], &[]).await; + let socket = harness.socket().await; + let channel = ApiTasksChannel::join_thread(&socket, "test-id") + .await + .expect("join channel"); + channel.leave().await.expect("leave channel"); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn api_tasks_channel_messages_and_pushes() { + let harness = support::harness().await; + let topic = "api:tasks:thread:test-id"; + harness + .register_channel(topic, &[], &["tasks_updated"]) + .await; + let socket = harness.socket().await; + let channel = ApiTasksChannel::join_thread(&socket, "test-id") + .await + .expect("join channel"); + let mut push_0 = channel.subscribe_tasks_updated(); + push_0 + .next() + .await + .expect("server push") + .expect("decode server push"); + channel.leave().await.expect("leave channel"); +} diff --git a/tests/generated_rest_contract.rs b/tests/generated_rest_contract.rs new file mode 100644 index 0000000..5917a5f --- /dev/null +++ b/tests/generated_rest_contract.rs @@ -0,0 +1,19367 @@ +// Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License. +// This file is auto-generated by @archastro/sdk-generator. Do not edit. +// Content hash: 130a6f14b29f + +//! Generated REST contract tests. +mod support; +use archastro::generated::*; + +#[test] +fn generated_support_is_linked() { + support::mark_all_used(); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_activity_feed_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ActivityFeedParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().activity_feed().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/activity_feed", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_activity_feed_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1ActivityFeedParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .activity_feed() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_activity_feed_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ActivityFeedParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .activity_feed() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_activity_feed_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1ActivityFeedParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .activity_feed() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_computers_computer_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_computers().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/agent_computers/{computer}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_computers_computer_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_computers() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_computers_computer_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_computers() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_computers_computer_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_computers() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_computers_computer_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_computers().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_computers/{computer}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_computers_computer_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_computers() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_computers_computer_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_computers() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_computers_computer_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_computers() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_computers_computer_exec_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentComputersComputerExecInput = + serde_json::from_str(r#"{"command":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .agent_computers() + .exec("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_computers/{computer}/exec", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_computers_computer_exec_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentComputersComputerExecInput = + serde_json::from_str(r#"{"command":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_computers() + .exec("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_computers_computer_exec_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentComputersComputerExecInput = + serde_json::from_str(r#"{"command":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_computers() + .exec("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_computers_computer_exec_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentComputersComputerExecInput = + serde_json::from_str(r#"{"command":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_computers() + .exec("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_computers_computer_exec_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentComputersComputerExecInput = + serde_json::from_str(r#"{"command":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_computers() + .exec("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_computers_computer_refresh_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_computers().refresh("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_computers/{computer}/refresh", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_computers_computer_refresh_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_computers() + .refresh("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_computers_computer_refresh_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_computers() + .refresh("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_computers_computer_refresh_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_computers() + .refresh("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_env_vars_env_var_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_env_vars().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/agent_env_vars/{env_var}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_env_vars_env_var_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_env_vars() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_env_vars_env_var_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_env_vars() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_env_vars_env_var_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_env_vars() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_env_vars_env_var_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_env_vars().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_env_vars/{env_var}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_env_vars_env_var_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_env_vars() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_env_vars_env_var_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_env_vars() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_env_vars_env_var_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_env_vars() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_env_vars_env_var_success() { + let client = support::rest_client(None).await; + let body: PatchApiV1AgentEnvVarsEnvVarInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client + .v1() + .agent_env_vars() + .update("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "PATCH /api/v1/agent_env_vars/{env_var}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_env_vars_env_var_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PatchApiV1AgentEnvVarsEnvVarInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_env_vars() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_env_vars_env_var_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PatchApiV1AgentEnvVarsEnvVarInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_env_vars() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_env_vars_env_var_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PatchApiV1AgentEnvVarsEnvVarInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_env_vars() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_env_vars_env_var_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PatchApiV1AgentEnvVarsEnvVarInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_env_vars() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_health_actions_health_action_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_health_actions().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_health_actions/{health_action}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_health_actions_health_action_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_health_actions() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_health_actions_health_action_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_health_actions() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_health_actions_health_action_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_health_actions() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_health_actions_health_action_verify_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .agent_health_actions() + .verify("test-value") + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_health_actions/{health_action}/verify", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_health_actions_health_action_verify_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_health_actions() + .verify("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_health_actions_health_action_verify_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_health_actions() + .verify("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_health_actions_health_action_verify_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_health_actions() + .verify("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_health_actions_health_action_verify_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .agent_health_actions() + .verify("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_installations_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentInstallationsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().agent_installations().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_installations", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_installations_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentInstallationsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_installations() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_installations_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentInstallationsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_installations() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_installations_installation_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_installations().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/agent_installations/{installation}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_installations_installation_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_installations() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_installations_installation_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_installations() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_installations_installation_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_installations() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_installations_installation_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_installations().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_installations/{installation}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_installations_installation_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_installations() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_installations_installation_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_installations() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_installations_installation_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_installations() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_activate_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .agent_installations() + .activate("test-value") + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_installations/{installation}/activate", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_activate_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_installations() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_activate_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_installations() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_activate_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_installations() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_activate_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .agent_installations() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_pause_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_installations().pause("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_installations/{installation}/pause", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_pause_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_installations() + .pause("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_pause_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_installations() + .pause("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_pause_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_installations() + .pause("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_pause_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .agent_installations() + .pause("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_suspend_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentInstallationsInstallationSuspendInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client + .v1() + .agent_installations() + .suspend("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_installations/{installation}/suspend", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_suspend_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentInstallationsInstallationSuspendInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_installations() + .suspend("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_suspend_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentInstallationsInstallationSuspendInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_installations() + .suspend("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_suspend_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentInstallationsInstallationSuspendInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_installations() + .suspend("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_suspend_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentInstallationsInstallationSuspendInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_installations() + .suspend("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_installations_installation_installation_sources_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .agent_installations() + .installation_sources("test-value") + .list() + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_installations/{installation}/installation_sources", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_installations_installation_installation_sources_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_installations() + .installation_sources("test-value") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_installations_installation_installation_sources_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_installations() + .installation_sources("test-value") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_installations_installation_installation_sources_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_installations() + .installation_sources("test-value") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_installation_sources_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentInstallationsInstallationInstallationSourcesInput = + serde_json::from_str(r#"{"payload":{},"type":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .agent_installations() + .installation_sources("test-value") + .create(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_installations/{installation}/installation_sources", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_installation_sources_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentInstallationsInstallationInstallationSourcesInput = + serde_json::from_str(r#"{"payload":{},"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_installations() + .installation_sources("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_installation_sources_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentInstallationsInstallationInstallationSourcesInput = + serde_json::from_str(r#"{"payload":{},"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_installations() + .installation_sources("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_installation_sources_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentInstallationsInstallationInstallationSourcesInput = + serde_json::from_str(r#"{"payload":{},"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_installations() + .installation_sources("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_installations_installation_installation_sources_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentInstallationsInstallationInstallationSourcesInput = + serde_json::from_str(r#"{"payload":{},"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_installations() + .installation_sources("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routine_runs_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentRoutineRunsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().agent_routine_runs().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_routine_runs", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routine_runs_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1AgentRoutineRunsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routine_runs() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routine_runs_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentRoutineRunsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routine_runs() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routine_runs_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentRoutineRunsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routine_runs() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routine_runs_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1AgentRoutineRunsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routine_runs() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentRoutinesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().agent_routines().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_routines", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentRoutinesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routines() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentRoutinesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routines() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_presets_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_routines().presets().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_routines/presets", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_presets_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_routines() + .presets() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_presets_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_routines() + .presets() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_routines_routine_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_routines().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/agent_routines/{routine}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_routines_routine_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_routines() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_routines_routine_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_routines() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_routines_routine_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_routines() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_routine_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_routines().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_routines/{routine}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_routine_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_routines() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_routine_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_routines() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_routine_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_routines() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_routines_routine_success() { + let client = support::rest_client(None).await; + let body: PatchApiV1AgentRoutinesRoutineInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client + .v1() + .agent_routines() + .update("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "PATCH /api/v1/agent_routines/{routine}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_routines_routine_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PatchApiV1AgentRoutinesRoutineInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_routines() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_routines_routine_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PatchApiV1AgentRoutinesRoutineInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_routines() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_routines_routine_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PatchApiV1AgentRoutinesRoutineInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_routines() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_routines_routine_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PatchApiV1AgentRoutinesRoutineInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_routines() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_activate_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_routines().activate("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_routines/{routine}/activate", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_activate_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_routines() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_activate_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_routines() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_activate_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_routines() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_activate_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .agent_routines() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_invoke_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentRoutinesRoutineInvokeInput = + serde_json::from_str(r#"{"message":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .agent_routines() + .invoke("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_routines/{routine}/invoke", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_invoke_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AgentRoutinesRoutineInvokeInput = + serde_json::from_str(r#"{"message":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_routines() + .invoke("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_invoke_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentRoutinesRoutineInvokeInput = + serde_json::from_str(r#"{"message":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_routines() + .invoke("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_invoke_error_402() { + let client = support::rest_client(Some(402)).await; + let body: PostApiV1AgentRoutinesRoutineInvokeInput = + serde_json::from_str(r#"{"message":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_routines() + .invoke("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 402); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_invoke_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentRoutinesRoutineInvokeInput = + serde_json::from_str(r#"{"message":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_routines() + .invoke("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_invoke_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentRoutinesRoutineInvokeInput = + serde_json::from_str(r#"{"message":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_routines() + .invoke("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_invoke_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1AgentRoutinesRoutineInvokeInput = + serde_json::from_str(r#"{"message":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_routines() + .invoke("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_invoke_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentRoutinesRoutineInvokeInput = + serde_json::from_str(r#"{"message":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_routines() + .invoke("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_pause_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_routines().pause("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_routines/{routine}/pause", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_pause_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_routines() + .pause("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_pause_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_routines() + .pause("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_routines_routine_pause_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_routines() + .pause("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_routine_runs_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentRoutinesRoutineRunsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .agent_routines() + .runs("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_routines/{routine}/runs", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_routine_runs_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1AgentRoutinesRoutineRunsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routines() + .runs("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_routine_runs_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentRoutinesRoutineRunsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routines() + .runs("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_routine_runs_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentRoutinesRoutineRunsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routines() + .runs("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_routine_runs_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1AgentRoutinesRoutineRunsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routines() + .runs("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_runs_run_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .agent_routines() + .agent_routine_runs() + .get("test-value") + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_routines/runs/{run}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_runs_run_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_routines() + .agent_routine_runs() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_runs_run_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_routines() + .agent_routine_runs() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_runs_run_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_routines() + .agent_routine_runs() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_runs_run_journal_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentRoutinesRunsRunJournalParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .agent_routines() + .agent_routine_runs() + .journal("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_routines/runs/{run}/journal", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_runs_run_journal_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1AgentRoutinesRunsRunJournalParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routines() + .agent_routine_runs() + .journal("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_runs_run_journal_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentRoutinesRunsRunJournalParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routines() + .agent_routine_runs() + .journal("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_runs_run_journal_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentRoutinesRunsRunJournalParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routines() + .agent_routine_runs() + .journal("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_routines_runs_run_journal_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1AgentRoutinesRunsRunJournalParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_routines() + .agent_routine_runs() + .journal("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_sessions_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentSessionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().agent_sessions().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_sessions", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_sessions_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentSessionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_sessions() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_sessions_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentSessionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_sessions() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_sessions_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1AgentSessionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_sessions() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentSessionsInput = + serde_json::from_str(r#"{"agent":"string","instructions":"string"}"#) + .expect("valid generated body"); + let result = client.v1().agent_sessions().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_sessions", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentSessionsInput = + serde_json::from_str(r#"{"agent":"string","instructions":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .agent_sessions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentSessionsInput = + serde_json::from_str(r#"{"agent":"string","instructions":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .agent_sessions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentSessionsInput = + serde_json::from_str(r#"{"agent":"string","instructions":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .agent_sessions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentSessionsInput = + serde_json::from_str(r#"{"agent":"string","instructions":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .agent_sessions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_sessions_agent_session_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_sessions().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/agent_sessions/{agent_session}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_sessions_agent_session_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_sessions() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_sessions_agent_session_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_sessions() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_sessions_agent_session_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_sessions() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_sessions_agent_session_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_sessions().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_sessions/{agent_session}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_sessions_agent_session_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_sessions() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_sessions_agent_session_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_sessions() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_sessions_agent_session_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_sessions() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_sessions_agent_session_success() { + let client = support::rest_client(None).await; + let body: PatchApiV1AgentSessionsAgentSessionInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client + .v1() + .agent_sessions() + .update("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "PATCH /api/v1/agent_sessions/{agent_session}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_sessions_agent_session_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PatchApiV1AgentSessionsAgentSessionInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_sessions() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_sessions_agent_session_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PatchApiV1AgentSessionsAgentSessionInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_sessions() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_sessions_agent_session_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PatchApiV1AgentSessionsAgentSessionInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_sessions() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_sessions_agent_session_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PatchApiV1AgentSessionsAgentSessionInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_sessions() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_agent_session_cancel_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_sessions().cancel("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_sessions/{agent_session}/cancel", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_agent_session_cancel_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_sessions() + .cancel("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_agent_session_cancel_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_sessions() + .cancel("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_agent_session_cancel_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_sessions() + .cancel("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_agent_session_message_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentSessionsAgentSessionMessageInput = + serde_json::from_str(r#"{"content":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .agent_sessions() + .message("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_sessions/{agent_session}/message", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_agent_session_message_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentSessionsAgentSessionMessageInput = + serde_json::from_str(r#"{"content":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_sessions() + .message("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_agent_session_message_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentSessionsAgentSessionMessageInput = + serde_json::from_str(r#"{"content":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_sessions() + .message("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_agent_session_message_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentSessionsAgentSessionMessageInput = + serde_json::from_str(r#"{"content":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_sessions() + .message("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_sessions_agent_session_message_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentSessionsAgentSessionMessageInput = + serde_json::from_str(r#"{"content":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agent_sessions() + .message("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_skills_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentSkillsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().agent_skills().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_skills", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_skills_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentSkillsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_skills() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_skills_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentSkillsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_skills() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_skills_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1AgentSkillsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_skills() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_skills_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentSkillsInput = + serde_json::from_str(r#"{"agent":"string","config":"string"}"#) + .expect("valid generated body"); + let result = client.v1().agent_skills().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_skills", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_skills_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentSkillsInput = + serde_json::from_str(r#"{"agent":"string","config":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .agent_skills() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_skills_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentSkillsInput = + serde_json::from_str(r#"{"agent":"string","config":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .agent_skills() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_skills_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentSkillsInput = + serde_json::from_str(r#"{"agent":"string","config":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .agent_skills() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_skills_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentSkillsInput = + serde_json::from_str(r#"{"agent":"string","config":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .agent_skills() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_skills_agent_skill_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_skills().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/agent_skills/{agent_skill}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_skills_agent_skill_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_skills() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_skills_agent_skill_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_skills() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_skills_agent_skill_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_skills() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_skills_agent_skill_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_skills().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_skills/{agent_skill}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_skills_agent_skill_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_skills() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_skills_agent_skill_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_skills() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_skills_agent_skill_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_skills() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_skills_agent_skill_success() { + let client = support::rest_client(None).await; + let body: PatchApiV1AgentSkillsAgentSkillInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().agent_skills().update("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "PATCH /api/v1/agent_skills/{agent_skill}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_skills_agent_skill_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PatchApiV1AgentSkillsAgentSkillInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_skills() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_skills_agent_skill_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PatchApiV1AgentSkillsAgentSkillInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_skills() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_skills_agent_skill_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PatchApiV1AgentSkillsAgentSkillInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_skills() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_skills_agent_skill_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PatchApiV1AgentSkillsAgentSkillInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_skills() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_skills_agent_skill_activate_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_skills().activate("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_skills/{agent_skill}/activate", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_skills_agent_skill_activate_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_skills() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_skills_agent_skill_activate_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_skills() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_skills_agent_skill_activate_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_skills() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_skills_agent_skill_deactivate_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_skills().deactivate("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_skills/{agent_skill}/deactivate", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_skills_agent_skill_deactivate_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_skills() + .deactivate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_skills_agent_skill_deactivate_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_skills() + .deactivate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_skills_agent_skill_deactivate_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_skills() + .deactivate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_tools_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentToolsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().agent_tools().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_tools", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_tools_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentToolsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_tools() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_tools_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentToolsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_tools() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_tools_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1AgentToolsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agent_tools() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_tools_catalog_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_tools().catalog().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_tools/catalog", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_tools_catalog_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_tools() + .catalog() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_tools_catalog_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_tools() + .catalog() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_tools_tool_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_tools().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/agent_tools/{tool}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_tools_tool_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_tools() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_tools_tool_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_tools() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agent_tools_tool_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_tools() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_tools_tool_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_tools().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agent_tools/{tool}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_tools_tool_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_tools() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_tools_tool_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_tools() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agent_tools_tool_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_tools() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_tools_tool_success() { + let client = support::rest_client(None).await; + let body: PatchApiV1AgentToolsToolInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().agent_tools().update("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "PATCH /api/v1/agent_tools/{tool}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_tools_tool_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PatchApiV1AgentToolsToolInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_tools() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_tools_tool_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PatchApiV1AgentToolsToolInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_tools() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_tools_tool_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PatchApiV1AgentToolsToolInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_tools() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agent_tools_tool_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PatchApiV1AgentToolsToolInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agent_tools() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_tools_tool_activate_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_tools().activate("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_tools/{tool}/activate", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_tools_tool_activate_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_tools() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_tools_tool_activate_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_tools() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_tools_tool_activate_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_tools() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_tools_tool_activate_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .agent_tools() + .activate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_tools_tool_deactivate_success() { + let client = support::rest_client(None).await; + let result = client.v1().agent_tools().deactivate("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agent_tools/{tool}/deactivate", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_tools_tool_deactivate_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agent_tools() + .deactivate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_tools_tool_deactivate_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agent_tools() + .deactivate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agent_tools_tool_deactivate_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agent_tools() + .deactivate("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().agents().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentsInput = serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().agents().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agents", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AgentsInput = serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentsInput = serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentsInput = serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentsInput = serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1AgentsInput = serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentsInput = serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agents_agent_success() { + let client = support::rest_client(None).await; + let result = client.v1().agents().delete("test-id").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/agents/{agent}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agents_agent_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agents() + .delete("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agents_agent_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agents() + .delete("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agents_agent_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agents() + .delete("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_success() { + let client = support::rest_client(None).await; + let result = client.v1().agents().get("test-id").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents/{agent}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agents() + .get("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agents() + .get("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agents() + .get("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agents_agent_success() { + let client = support::rest_client(None).await; + let body: PatchApiV1AgentsAgentInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().agents().update("test-id", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "PATCH /api/v1/agents/{agent}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agents_agent_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PatchApiV1AgentsAgentInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .update("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agents_agent_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PatchApiV1AgentsAgentInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .update("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agents_agent_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PatchApiV1AgentsAgentInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .update("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agents_agent_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PatchApiV1AgentsAgentInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .update("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_health_actions_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentsAgentAgentHealthActionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .agents() + .agent_health_actions("test-id", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents/{agent}/agent_health_actions", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_health_actions_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentsAgentAgentHealthActionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .agent_health_actions("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_health_actions_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentsAgentAgentHealthActionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .agent_health_actions("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_health_actions_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1AgentsAgentAgentHealthActionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .agent_health_actions("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_routines_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentsAgentAgentRoutinesInput = + serde_json::from_str(r#"{"handler_type":"string","name":"Example Name"}"#) + .expect("valid generated body"); + let result = client.v1().agents().agent_routines("test-id", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agents/{agent}/agent_routines", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_routines_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentsAgentAgentRoutinesInput = + serde_json::from_str(r#"{"handler_type":"string","name":"Example Name"}"#) + .expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_routines("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_routines_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentsAgentAgentRoutinesInput = + serde_json::from_str(r#"{"handler_type":"string","name":"Example Name"}"#) + .expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_routines("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_routines_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentsAgentAgentRoutinesInput = + serde_json::from_str(r#"{"handler_type":"string","name":"Example Name"}"#) + .expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_routines("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_routines_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentsAgentAgentRoutinesInput = + serde_json::from_str(r#"{"handler_type":"string","name":"Example Name"}"#) + .expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_routines("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_export_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentsAgentExportParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().agents().export("test-id", Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents/{agent}/export", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_export_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentsAgentExportParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .export("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_export_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentsAgentExportParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .export("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_export_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1AgentsAgentExportParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .export("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_health_success() { + let client = support::rest_client(None).await; + let result = client.v1().agents().health("test-id").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents/{agent}/health", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_health_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agents() + .health("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_health_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agents() + .health("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_health_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agents() + .health("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_search_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentsAgentSearchInput = + serde_json::from_str(r#"{"query":"string"}"#).expect("valid generated body"); + let result = client.v1().agents().search("test-id", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agents/{agent}/search", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_search_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentsAgentSearchInput = + serde_json::from_str(r#"{"query":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .search("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_search_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentsAgentSearchInput = + serde_json::from_str(r#"{"query":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .search("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_search_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentsAgentSearchInput = + serde_json::from_str(r#"{"query":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .search("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_threads_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentsAgentThreadsInput = serde_json::from_str(r#"{"thread":{"create_legacy_agent":true,"description":"An example description.","is_unlisted":true,"key":"string","members":[{"id":"string","type":"user"}],"metadata":{"key":"value"},"muted":true,"org_id":"string","profile_picture":{"data":"string","filename":"string","mime_type":"application/json"},"settings":{"agent_enabled":true},"slug":"example-slug","title":"Example Title","visibility":"team"}}"#).expect("valid generated body"); + let result = client.v1().agents().threads("test-id", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agents/{agent}/threads", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_threads_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentsAgentThreadsInput = serde_json::from_str(r#"{"thread":{"create_legacy_agent":true,"description":"An example description.","is_unlisted":true,"key":"string","members":[{"id":"string","type":"user"}],"metadata":{"key":"value"},"muted":true,"org_id":"string","profile_picture":{"data":"string","filename":"string","mime_type":"application/json"},"settings":{"agent_enabled":true},"slug":"example-slug","title":"Example Title","visibility":"team"}}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .threads("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_threads_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentsAgentThreadsInput = serde_json::from_str(r#"{"thread":{"create_legacy_agent":true,"description":"An example description.","is_unlisted":true,"key":"string","members":[{"id":"string","type":"user"}],"metadata":{"key":"value"},"muted":true,"org_id":"string","profile_picture":{"data":"string","filename":"string","mime_type":"application/json"},"settings":{"agent_enabled":true},"slug":"example-slug","title":"Example Title","visibility":"team"}}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .threads("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_threads_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentsAgentThreadsInput = serde_json::from_str(r#"{"thread":{"create_legacy_agent":true,"description":"An example description.","is_unlisted":true,"key":"string","members":[{"id":"string","type":"user"}],"metadata":{"key":"value"},"muted":true,"org_id":"string","profile_picture":{"data":"string","filename":"string","mime_type":"application/json"},"settings":{"agent_enabled":true},"slug":"example-slug","title":"Example Title","visibility":"team"}}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .threads("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_threads_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentsAgentThreadsInput = serde_json::from_str(r#"{"thread":{"create_legacy_agent":true,"description":"An example description.","is_unlisted":true,"key":"string","members":[{"id":"string","type":"user"}],"metadata":{"key":"value"},"muted":true,"org_id":"string","profile_picture":{"data":"string","filename":"string","mime_type":"application/json"},"settings":{"agent_enabled":true},"slug":"example-slug","title":"Example Title","visibility":"team"}}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .threads("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_upgrade_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentsAgentUpgradeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().agents().upgrade("test-id", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agents/{agent}/upgrade", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_upgrade_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AgentsAgentUpgradeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .upgrade("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_upgrade_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentsAgentUpgradeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .upgrade("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_upgrade_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentsAgentUpgradeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .upgrade("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_upgrade_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentsAgentUpgradeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .upgrade("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_upgrade_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1AgentsAgentUpgradeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .upgrade("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_upgrade_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentsAgentUpgradeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .upgrade("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_computers_success() { + let client = support::rest_client(None).await; + let result = client.v1().agents().agent_computers("test-id").list().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents/{agent}/agent_computers", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_computers_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agents() + .agent_computers("test-id") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_computers_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agents() + .agent_computers("test-id") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_computers_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agents() + .agent_computers("test-id") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_computers_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentsAgentAgentComputersInput = + serde_json::from_str(r#"{"name":"Example Name"}"#).expect("valid generated body"); + let result = client + .v1() + .agents() + .agent_computers("test-id") + .create(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agents/{agent}/agent_computers", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_computers_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentsAgentAgentComputersInput = + serde_json::from_str(r#"{"name":"Example Name"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_computers("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_computers_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentsAgentAgentComputersInput = + serde_json::from_str(r#"{"name":"Example Name"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_computers("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_computers_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentsAgentAgentComputersInput = + serde_json::from_str(r#"{"name":"Example Name"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_computers("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_computers_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentsAgentAgentComputersInput = + serde_json::from_str(r#"{"name":"Example Name"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_computers("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_env_vars_success() { + let client = support::rest_client(None).await; + let result = client.v1().agents().agent_env_vars("test-id").list().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents/{agent}/agent_env_vars", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_env_vars_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agents() + .agent_env_vars("test-id") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_env_vars_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agents() + .agent_env_vars("test-id") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_env_vars_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agents() + .agent_env_vars("test-id") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_env_vars_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentsAgentAgentEnvVarsInput = + serde_json::from_str(r#"{"key":"string","value":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .agents() + .agent_env_vars("test-id") + .create(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agents/{agent}/agent_env_vars", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_env_vars_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentsAgentAgentEnvVarsInput = + serde_json::from_str(r#"{"key":"string","value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_env_vars("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_env_vars_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentsAgentAgentEnvVarsInput = + serde_json::from_str(r#"{"key":"string","value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_env_vars("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_env_vars_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentsAgentAgentEnvVarsInput = + serde_json::from_str(r#"{"key":"string","value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_env_vars("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_env_vars_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentsAgentAgentEnvVarsInput = + serde_json::from_str(r#"{"key":"string","value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_env_vars("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_installations_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .agents() + .agent_installations("test-id") + .list() + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents/{agent}/agent_installations", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_installations_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agents() + .agent_installations("test-id") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_installations_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agents() + .agent_installations("test-id") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_installations_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agents() + .agent_installations("test-id") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_installations_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentsAgentAgentInstallationsInput = + serde_json::from_str(r#"{"kind":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .agents() + .agent_installations("test-id") + .create(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agents/{agent}/agent_installations", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_installations_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentsAgentAgentInstallationsInput = + serde_json::from_str(r#"{"kind":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_installations("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_installations_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentsAgentAgentInstallationsInput = + serde_json::from_str(r#"{"kind":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_installations("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_installations_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentsAgentAgentInstallationsInput = + serde_json::from_str(r#"{"kind":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_installations("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_installations_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentsAgentAgentInstallationsInput = + serde_json::from_str(r#"{"kind":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_installations("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_installations_kinds_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .agents() + .agent_installations("test-id") + .kinds() + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents/{agent}/agent_installations/kinds", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_installations_kinds_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agents() + .agent_installations("test-id") + .kinds() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_installations_kinds_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agents() + .agent_installations("test-id") + .kinds() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_tools_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentsAgentAgentToolsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .agents() + .agent_tools("test-id") + .list(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents/{agent}/agent_tools", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_tools_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentsAgentAgentToolsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .agent_tools("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_tools_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentsAgentAgentToolsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .agent_tools("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_tools_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1AgentsAgentAgentToolsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .agent_tools("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_tools_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentsAgentAgentToolsInput = + serde_json::from_str(r#"{"kind":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .agents() + .agent_tools("test-id") + .create(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agents/{agent}/agent_tools", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_tools_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentsAgentAgentToolsInput = + serde_json::from_str(r#"{"kind":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_tools("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_tools_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentsAgentAgentToolsInput = + serde_json::from_str(r#"{"kind":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_tools("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_tools_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentsAgentAgentToolsInput = + serde_json::from_str(r#"{"kind":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_tools("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_agent_tools_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentsAgentAgentToolsInput = + serde_json::from_str(r#"{"kind":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_tools("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_working_memory_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentsAgentAgentWorkingMemoryParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .agents() + .agent_working_memory("test-id") + .list(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents/{agent}/agent_working_memory", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_working_memory_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentsAgentAgentWorkingMemoryParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .agent_working_memory("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_working_memory_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentsAgentAgentWorkingMemoryParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .agent_working_memory("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_agent_working_memory_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1AgentsAgentAgentWorkingMemoryParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .agent_working_memory("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agents_agent_agent_working_memory_entry_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .agents() + .agent_working_memory("test-id") + .delete("test-value") + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/agents/{agent}/agent_working_memory/{entry}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agents_agent_agent_working_memory_entry_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agents() + .agent_working_memory("test-id") + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agents_agent_agent_working_memory_entry_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agents() + .agent_working_memory("test-id") + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_agents_agent_agent_working_memory_entry_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agents() + .agent_working_memory("test-id") + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agents_agent_agent_working_memory_entry_success() { + let client = support::rest_client(None).await; + let body: PatchApiV1AgentsAgentAgentWorkingMemoryEntryInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client + .v1() + .agents() + .agent_working_memory("test-id") + .update("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "PATCH /api/v1/agents/{agent}/agent_working_memory/{entry}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agents_agent_agent_working_memory_entry_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PatchApiV1AgentsAgentAgentWorkingMemoryEntryInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_working_memory("test-id") + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agents_agent_agent_working_memory_entry_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PatchApiV1AgentsAgentAgentWorkingMemoryEntryInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_working_memory("test-id") + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agents_agent_agent_working_memory_entry_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PatchApiV1AgentsAgentAgentWorkingMemoryEntryInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_working_memory("test-id") + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_agents_agent_agent_working_memory_entry_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PatchApiV1AgentsAgentAgentWorkingMemoryEntryInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .agent_working_memory("test-id") + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_schedules_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentsAgentSchedulesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .agents() + .schedules("test-id") + .list(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents/{agent}/schedules", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_schedules_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1AgentsAgentSchedulesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .schedules("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_schedules_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentsAgentSchedulesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .schedules("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_schedules_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentsAgentSchedulesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .schedules("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_schedules_schedule_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .agents() + .schedules("test-id") + .get("test-value") + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents/{agent}/schedules/{schedule}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_schedules_schedule_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .agents() + .schedules("test-id") + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_schedules_schedule_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .agents() + .schedules("test-id") + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_schedules_schedule_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .agents() + .schedules("test-id") + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_work_items_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AgentsAgentWorkItemsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .agents() + .work_items("test-id") + .list(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/agents/{agent}/work_items", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_work_items_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1AgentsAgentWorkItemsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .work_items("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_work_items_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AgentsAgentWorkItemsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .work_items("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_work_items_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AgentsAgentWorkItemsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .work_items("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_work_items_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1AgentsAgentWorkItemsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .work_items("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_agents_agent_work_items_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1AgentsAgentWorkItemsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .agents() + .work_items("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_work_items_claim_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AgentsAgentWorkItemsClaimInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .agents() + .work_items("test-id") + .claim(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/agents/{agent}/work_items/claim", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_work_items_claim_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AgentsAgentWorkItemsClaimInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .work_items("test-id") + .claim(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_work_items_claim_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AgentsAgentWorkItemsClaimInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .work_items("test-id") + .claim(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_work_items_claim_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AgentsAgentWorkItemsClaimInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .work_items("test-id") + .claim(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_agents_agent_work_items_claim_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AgentsAgentWorkItemsClaimInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .agents() + .work_items("test-id") + .claim(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_artifacts_artifact_success() { + let client = support::rest_client(None).await; + let result = client.v1().artifacts().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/artifacts/{artifact}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_artifacts_artifact_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .artifacts() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_artifacts_artifact_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .artifacts() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_artifacts_artifact_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .artifacts() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_artifacts_artifact_success() { + let client = support::rest_client(None).await; + let result = client.v1().artifacts().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/artifacts/{artifact}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_artifacts_artifact_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .artifacts() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_artifacts_artifact_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .artifacts() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_artifacts_artifact_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .artifacts() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_artifacts_artifact_success() { + let client = support::rest_client(None).await; + let body: PutApiV1ArtifactsArtifactInput = + serde_json::from_str(r#"{"from_version":1}"#).expect("valid generated body"); + let result = client.v1().artifacts().replace("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "PUT /api/v1/artifacts/{artifact}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_artifacts_artifact_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PutApiV1ArtifactsArtifactInput = + serde_json::from_str(r#"{"from_version":1}"#).expect("valid generated body"); + let error = client + .v1() + .artifacts() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_artifacts_artifact_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PutApiV1ArtifactsArtifactInput = + serde_json::from_str(r#"{"from_version":1}"#).expect("valid generated body"); + let error = client + .v1() + .artifacts() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_artifacts_artifact_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PutApiV1ArtifactsArtifactInput = + serde_json::from_str(r#"{"from_version":1}"#).expect("valid generated body"); + let error = client + .v1() + .artifacts() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_artifacts_artifact_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PutApiV1ArtifactsArtifactInput = + serde_json::from_str(r#"{"from_version":1}"#).expect("valid generated body"); + let error = client + .v1() + .artifacts() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_artifacts_artifact_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PutApiV1ArtifactsArtifactInput = + serde_json::from_str(r#"{"from_version":1}"#).expect("valid generated body"); + let error = client + .v1() + .artifacts() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_artifacts_artifact_archive_success() { + let client = support::rest_client(None).await; + let result = client.v1().artifacts().archive("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/artifacts/{artifact}/archive", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_artifacts_artifact_archive_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .artifacts() + .archive("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_artifacts_artifact_archive_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .artifacts() + .archive("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_artifacts_artifact_archive_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .artifacts() + .archive("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_artifacts_artifact_content_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ArtifactsArtifactContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .artifacts() + .content("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/artifacts/{artifact}/content", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_artifacts_artifact_content_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ArtifactsArtifactContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .artifacts() + .content("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_artifacts_artifact_content_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1ArtifactsArtifactContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .artifacts() + .content("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_artifacts_artifact_content_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1ArtifactsArtifactContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .artifacts() + .content("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_artifacts_artifact_content_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1ArtifactsArtifactContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .artifacts() + .content("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_automation_runs_automation_run_success() { + let client = support::rest_client(None).await; + let result = client.v1().automation_runs().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/automation_runs/{automation_run}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_automation_runs_automation_run_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .automation_runs() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_automation_runs_automation_run_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .automation_runs() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_automation_runs_automation_run_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .automation_runs() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_automation_runs_automation_run_journal_success() { + let client = support::rest_client(None).await; + let params: GetApiV1AutomationRunsAutomationRunJournalParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .automation_runs() + .journal("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/automation_runs/{automation_run}/journal", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_automation_runs_automation_run_journal_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1AutomationRunsAutomationRunJournalParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .automation_runs() + .journal("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_automation_runs_automation_run_journal_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1AutomationRunsAutomationRunJournalParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .automation_runs() + .journal("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_automation_runs_automation_run_journal_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1AutomationRunsAutomationRunJournalParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .automation_runs() + .journal("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_automation_runs_automation_run_journal_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1AutomationRunsAutomationRunJournalParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .automation_runs() + .journal("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_automations_automation_invoke_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AutomationsAutomationInvokeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().automations().invoke("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/automations/{automation}/invoke", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_automations_automation_invoke_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AutomationsAutomationInvokeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .automations() + .invoke("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_automations_automation_invoke_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AutomationsAutomationInvokeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .automations() + .invoke("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_automations_automation_invoke_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AutomationsAutomationInvokeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .automations() + .invoke("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_automations_automation_invoke_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AutomationsAutomationInvokeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .automations() + .invoke("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_automations_automation_invoke_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1AutomationsAutomationInvokeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .automations() + .invoke("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_automations_automation_invoke_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AutomationsAutomationInvokeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .automations() + .invoke("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_bug_reports_success() { + let client = support::rest_client(None).await; + let body: PostApiV1BugReportsInput = serde_json::from_str( + r#"{"client":"string","client_version":"string","description":"An example description."}"#, + ) + .expect("valid generated body"); + let result = client.v1().bug_reports().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/bug_reports", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_bug_reports_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1BugReportsInput = serde_json::from_str( + r#"{"client":"string","client_version":"string","description":"An example description."}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .bug_reports() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_bug_reports_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1BugReportsInput = serde_json::from_str( + r#"{"client":"string","client_version":"string","description":"An example description."}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .bug_reports() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_bug_reports_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1BugReportsInput = serde_json::from_str( + r#"{"client":"string","client_version":"string","description":"An example description."}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .bug_reports() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_bug_reports_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostApiV1BugReportsInput = serde_json::from_str( + r#"{"client":"string","client_version":"string","description":"An example description."}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .bug_reports() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ConfigParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().config().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/config", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1ConfigParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ConfigParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_success() { + let client = support::rest_client(None).await; + let body: PostApiV1ConfigInput = serde_json::from_str( + r#"{"kind":"string","mime_type":"application/json","raw_content":"string"}"#, + ) + .expect("valid generated body"); + let result = client.v1().config().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/config", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1ConfigInput = serde_json::from_str( + r#"{"kind":"string","mime_type":"application/json","raw_content":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .config() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1ConfigInput = serde_json::from_str( + r#"{"kind":"string","mime_type":"application/json","raw_content":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .config() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1ConfigInput = serde_json::from_str( + r#"{"kind":"string","mime_type":"application/json","raw_content":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .config() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1ConfigInput = serde_json::from_str( + r#"{"kind":"string","mime_type":"application/json","raw_content":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .config() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_encrypt_secret_success() { + let client = support::rest_client(None).await; + let body: PostApiV1ConfigEncryptSecretInput = + serde_json::from_str(r#"{"plaintext":"string"}"#).expect("valid generated body"); + let result = client.v1().config().encrypt_secret(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/config/encrypt_secret", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_encrypt_secret_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1ConfigEncryptSecretInput = + serde_json::from_str(r#"{"plaintext":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .encrypt_secret(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_encrypt_secret_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1ConfigEncryptSecretInput = + serde_json::from_str(r#"{"plaintext":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .encrypt_secret(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_encrypt_secret_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1ConfigEncryptSecretInput = + serde_json::from_str(r#"{"plaintext":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .encrypt_secret(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_facets_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ConfigFacetsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().config().facets(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/config/facets", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_facets_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ConfigFacetsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .facets(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_facets_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1ConfigFacetsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .facets(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_validate_success() { + let client = support::rest_client(None).await; + let body: PostApiV1ConfigValidateInput = serde_json::from_str( + r#"{"kind":"string","mime_type":"application/json","raw_content":"string"}"#, + ) + .expect("valid generated body"); + let result = client.v1().config().validate(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/config/validate", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_validate_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1ConfigValidateInput = serde_json::from_str( + r#"{"kind":"string","mime_type":"application/json","raw_content":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .config() + .validate(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_validate_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1ConfigValidateInput = serde_json::from_str( + r#"{"kind":"string","mime_type":"application/json","raw_content":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .config() + .validate(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_validate_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1ConfigValidateInput = serde_json::from_str( + r#"{"kind":"string","mime_type":"application/json","raw_content":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .config() + .validate(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_config_config_success() { + let client = support::rest_client(None).await; + let result = client.v1().config().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/config/{config}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_config_config_error_400() { + let client = support::rest_client(Some(400)).await; + let error = client + .v1() + .config() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_config_config_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .config() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_config_config_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .config() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_config_config_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .config() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_config_config_error_409() { + let client = support::rest_client(Some(409)).await; + let error = client + .v1() + .config() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_config_config_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .config() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ConfigConfigParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().config().get("test-value", Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/config/{config}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1ConfigConfigParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .get("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ConfigConfigParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .get("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1ConfigConfigParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .get("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1ConfigConfigParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .get("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1ConfigConfigParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .get("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_config_config_success() { + let client = support::rest_client(None).await; + let body: PatchApiV1ConfigConfigInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().config().update("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "PATCH /api/v1/config/{config}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_config_config_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PatchApiV1ConfigConfigInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_config_config_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PatchApiV1ConfigConfigInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_config_config_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PatchApiV1ConfigConfigInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_config_config_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PatchApiV1ConfigConfigInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_config_config_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PatchApiV1ConfigConfigInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_config_config_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PatchApiV1ConfigConfigInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_archive_success() { + let client = support::rest_client(None).await; + let body: PostApiV1ConfigConfigArchiveInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().config().archive("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/config/{config}/archive", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_archive_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1ConfigConfigArchiveInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .archive("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_archive_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1ConfigConfigArchiveInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .archive("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_archive_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1ConfigConfigArchiveInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .archive("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_archive_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1ConfigConfigArchiveInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .archive("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_archive_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1ConfigConfigArchiveInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .archive("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_change_owner_success() { + let client = support::rest_client(None).await; + let body: PostApiV1ConfigConfigChangeOwnerInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().config().change_owner("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/config/{config}/change_owner", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_change_owner_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1ConfigConfigChangeOwnerInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .change_owner("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_change_owner_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1ConfigConfigChangeOwnerInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .change_owner("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_change_owner_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1ConfigConfigChangeOwnerInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .change_owner("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_change_owner_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1ConfigConfigChangeOwnerInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .change_owner("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_change_owner_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1ConfigConfigChangeOwnerInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .change_owner("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_content_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ConfigConfigContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .config() + .content("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/config/{config}/content", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_content_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1ConfigConfigContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .content("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_content_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ConfigConfigContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .content("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_content_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1ConfigConfigContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .content("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_content_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1ConfigConfigContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .content("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_content_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1ConfigConfigContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .content("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_unarchive_success() { + let client = support::rest_client(None).await; + let body: PostApiV1ConfigConfigUnarchiveInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().config().unarchive("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/config/{config}/unarchive", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_unarchive_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1ConfigConfigUnarchiveInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .unarchive("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_unarchive_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1ConfigConfigUnarchiveInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .unarchive("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_unarchive_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1ConfigConfigUnarchiveInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .unarchive("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_unarchive_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1ConfigConfigUnarchiveInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .unarchive("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_config_unarchive_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1ConfigConfigUnarchiveInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .unarchive("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_versions_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ConfigConfigVersionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .config() + .versions("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/config/{config}/versions", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_versions_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1ConfigConfigVersionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .versions("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_versions_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ConfigConfigVersionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .versions("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_versions_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1ConfigConfigVersionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .versions("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_versions_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1ConfigConfigVersionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .versions("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_config_versions_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1ConfigConfigVersionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .versions("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_kinds_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ConfigKindsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().config().kinds().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/config/kinds", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_kinds_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ConfigKindsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .kinds() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_kinds_kind_schema_success() { + let client = support::rest_client(None).await; + let result = client.v1().config().kinds().schema("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/config/kinds/{kind}/schema", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_kinds_kind_schema_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .config() + .kinds() + .schema("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_kinds_kind_schema_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .config() + .kinds() + .schema("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_system_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ConfigSystemParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().config().system().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/config/system", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_system_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ConfigSystemParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .config() + .system() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_system_facets_success() { + let client = support::rest_client(None).await; + let result = client.v1().config().system().facets().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/config/system/facets", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_system_facets_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .config() + .system() + .facets() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_system_system_success() { + let client = support::rest_client(None).await; + let result = client.v1().config().system().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/config/system/{system}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_system_system_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .config() + .system() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_config_system_system_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .config() + .system() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_system_system_clone_success() { + let client = support::rest_client(None).await; + let body: PostApiV1ConfigSystemSystemCloneInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client + .v1() + .config() + .system() + .clone("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/config/system/{system}/clone", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_system_system_clone_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1ConfigSystemSystemCloneInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .system() + .clone("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_system_system_clone_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1ConfigSystemSystemCloneInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .system() + .clone("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_system_system_clone_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1ConfigSystemSystemCloneInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .system() + .clone("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_config_system_system_clone_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1ConfigSystemSystemCloneInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .config() + .system() + .clone("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_custom_objects_success() { + let client = support::rest_client(None).await; + let params: GetApiV1CustomObjectsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().custom_objects().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/custom_objects", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_custom_objects_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1CustomObjectsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .custom_objects() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_custom_objects_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1CustomObjectsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .custom_objects() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_custom_objects_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1CustomObjectsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .custom_objects() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_custom_objects_success() { + let client = support::rest_client(None).await; + let body: PostApiV1CustomObjectsInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().custom_objects().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/custom_objects", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_custom_objects_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1CustomObjectsInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .custom_objects() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_custom_objects_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1CustomObjectsInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .custom_objects() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_custom_objects_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1CustomObjectsInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .custom_objects() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_custom_objects_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1CustomObjectsInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .custom_objects() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_custom_objects_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1CustomObjectsInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .custom_objects() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_custom_objects_object_success() { + let client = support::rest_client(None).await; + let result = client.v1().custom_objects().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/custom_objects/{object}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_custom_objects_object_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .custom_objects() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_custom_objects_object_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .custom_objects() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_custom_objects_object_success() { + let client = support::rest_client(None).await; + let params: GetApiV1CustomObjectsObjectParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .custom_objects() + .get("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/custom_objects/{object}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_custom_objects_object_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1CustomObjectsObjectParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .custom_objects() + .get("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_custom_objects_object_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1CustomObjectsObjectParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .custom_objects() + .get("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_custom_objects_object_success() { + let client = support::rest_client(None).await; + let body: PutApiV1CustomObjectsObjectInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client + .v1() + .custom_objects() + .replace("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "PUT /api/v1/custom_objects/{object}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_custom_objects_object_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PutApiV1CustomObjectsObjectInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .custom_objects() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_custom_objects_object_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PutApiV1CustomObjectsObjectInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .custom_objects() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_custom_objects_object_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PutApiV1CustomObjectsObjectInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .custom_objects() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_custom_objects_object_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PutApiV1CustomObjectsObjectInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .custom_objects() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_extractions_success() { + let client = support::rest_client(None).await; + let body: PostApiV1ExtractionsInput = + serde_json::from_str(r#"{"destination_kind":"config"}"#).expect("valid generated body"); + let result = client.v1().extractions().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/extractions", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_extractions_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1ExtractionsInput = + serde_json::from_str(r#"{"destination_kind":"config"}"#).expect("valid generated body"); + let error = client + .v1() + .extractions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_extractions_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1ExtractionsInput = + serde_json::from_str(r#"{"destination_kind":"config"}"#).expect("valid generated body"); + let error = client + .v1() + .extractions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_extractions_error_502() { + let client = support::rest_client(Some(502)).await; + let body: PostApiV1ExtractionsInput = + serde_json::from_str(r#"{"destination_kind":"config"}"#).expect("valid generated body"); + let error = client + .v1() + .extractions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 502); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_extractions_extraction_success() { + let client = support::rest_client(None).await; + let result = client.v1().extractions().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/extractions/{extraction}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_extractions_extraction_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .extractions() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_files_success() { + let client = support::rest_client(None).await; + let body: PostApiV1FilesInput = serde_json::from_str( + r#"{"content_type":"application/json","data":"string","filename":"string"}"#, + ) + .expect("valid generated body"); + let result = client.v1().files().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/files", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_files_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1FilesInput = serde_json::from_str( + r#"{"content_type":"application/json","data":"string","filename":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .files() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_files_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1FilesInput = serde_json::from_str( + r#"{"content_type":"application/json","data":"string","filename":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .files() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_files_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1FilesInput = serde_json::from_str( + r#"{"content_type":"application/json","data":"string","filename":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .files() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_files_file_success() { + let client = support::rest_client(None).await; + let body: PatchApiV1FilesFileInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().files().update("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "PATCH /api/v1/files/{file}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_files_file_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PatchApiV1FilesFileInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .files() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_files_file_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PatchApiV1FilesFileInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .files() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_files_file_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PatchApiV1FilesFileInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .files() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_files_file_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PatchApiV1FilesFileInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .files() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_files_file_avatar_success() { + let client = support::rest_client(None).await; + let params: GetApiV1FilesFileAvatarParams = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated params"); + let result = client.v1().files().avatar("test-value", ¶ms).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/files/{file}/avatar", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_files_file_avatar_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1FilesFileAvatarParams = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .files() + .avatar("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_files_file_org_logo_success() { + let client = support::rest_client(None).await; + let params: GetApiV1FilesFileOrgLogoParams = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated params"); + let result = client.v1().files().org_logo("test-value", ¶ms).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/files/{file}/org_logo", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_files_file_org_logo_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1FilesFileOrgLogoParams = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .files() + .org_logo("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_files_file_share_success() { + let client = support::rest_client(None).await; + let params: GetApiV1FilesFileShareParams = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated params"); + let result = client.v1().files().share("test-value", ¶ms).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/files/{file}/share", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_files_file_share_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1FilesFileShareParams = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .files() + .share("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_installation_sources_source_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .installation_sources() + .delete("test-value") + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/installation_sources/{source}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_installation_sources_source_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .installation_sources() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_installation_sources_source_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .installation_sources() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_installation_sources_source_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .installation_sources() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_invites_accept_success() { + let client = support::rest_client(None).await; + let body: PostApiV1InvitesAcceptInput = + serde_json::from_str(r#"{"key":"string"}"#).expect("valid generated body"); + let result = client.v1().invites().accept(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/invites/accept", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_invites_accept_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1InvitesAcceptInput = + serde_json::from_str(r#"{"key":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .invites() + .accept(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_invites_accept_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1InvitesAcceptInput = + serde_json::from_str(r#"{"key":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .invites() + .accept(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_invites_accept_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1InvitesAcceptInput = + serde_json::from_str(r#"{"key":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .invites() + .accept(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_invites_accept_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1InvitesAcceptInput = + serde_json::from_str(r#"{"key":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .invites() + .accept(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_invites_accept_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1InvitesAcceptInput = + serde_json::from_str(r#"{"key":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .invites() + .accept(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_invites_accept_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostApiV1InvitesAcceptInput = + serde_json::from_str(r#"{"key":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .invites() + .accept(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_documents_success() { + let client = support::rest_client(None).await; + let params: GetApiV1KnowledgeDocumentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().knowledge_documents().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/knowledge_documents", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_documents_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1KnowledgeDocumentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .knowledge_documents() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_documents_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1KnowledgeDocumentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .knowledge_documents() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_knowledge_documents_document_success() { + let client = support::rest_client(None).await; + let result = client.v1().knowledge_documents().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/knowledge_documents/{document}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_knowledge_documents_document_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .knowledge_documents() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_knowledge_documents_document_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .knowledge_documents() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_knowledge_documents_document_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .knowledge_documents() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_documents_document_success() { + let client = support::rest_client(None).await; + let result = client.v1().knowledge_documents().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/knowledge_documents/{document}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_documents_document_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .knowledge_documents() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_documents_document_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .knowledge_documents() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_documents_document_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .knowledge_documents() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_knowledge_documents_document_success() { + let client = support::rest_client(None).await; + let body: PatchApiV1KnowledgeDocumentsDocumentInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client + .v1() + .knowledge_documents() + .update("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "PATCH /api/v1/knowledge_documents/{document}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_knowledge_documents_document_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PatchApiV1KnowledgeDocumentsDocumentInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_documents() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_knowledge_documents_document_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PatchApiV1KnowledgeDocumentsDocumentInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_documents() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_knowledge_documents_document_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PatchApiV1KnowledgeDocumentsDocumentInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_documents() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_knowledge_documents_document_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PatchApiV1KnowledgeDocumentsDocumentInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_documents() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_knowledge_documents_document_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PatchApiV1KnowledgeDocumentsDocumentInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_documents() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_documents_document_content_success() { + let client = support::rest_client(None).await; + let params: GetApiV1KnowledgeDocumentsDocumentContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .knowledge_documents() + .content("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/knowledge_documents/{document}/content", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_documents_document_content_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1KnowledgeDocumentsDocumentContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .knowledge_documents() + .content("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_documents_document_content_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1KnowledgeDocumentsDocumentContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .knowledge_documents() + .content("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_documents_document_content_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1KnowledgeDocumentsDocumentContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .knowledge_documents() + .content("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_documents_document_content_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1KnowledgeDocumentsDocumentContentParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .knowledge_documents() + .content("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_ingestions_ingestion_success() { + let client = support::rest_client(None).await; + let result = client.v1().knowledge_ingestions().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/knowledge_ingestions/{ingestion}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_ingestions_ingestion_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .knowledge_ingestions() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_ingestions_ingestion_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .knowledge_ingestions() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_ingestions_ingestion_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .knowledge_ingestions() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_sources_success() { + let client = support::rest_client(None).await; + let params: GetApiV1KnowledgeSourcesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().knowledge_sources().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/knowledge_sources", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_sources_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1KnowledgeSourcesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .knowledge_sources() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_sources_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1KnowledgeSourcesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .knowledge_sources() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_knowledge_sources_success() { + let client = support::rest_client(None).await; + let body: PostApiV1KnowledgeSourcesInput = + serde_json::from_str(r#"{"type":"string"}"#).expect("valid generated body"); + let result = client.v1().knowledge_sources().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/knowledge_sources", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_knowledge_sources_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1KnowledgeSourcesInput = + serde_json::from_str(r#"{"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_sources() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_knowledge_sources_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1KnowledgeSourcesInput = + serde_json::from_str(r#"{"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_sources() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_knowledge_sources_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1KnowledgeSourcesInput = + serde_json::from_str(r#"{"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_sources() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_knowledge_sources_source_success() { + let client = support::rest_client(None).await; + let result = client.v1().knowledge_sources().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/knowledge_sources/{source}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_knowledge_sources_source_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .knowledge_sources() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_knowledge_sources_source_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .knowledge_sources() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_knowledge_sources_source_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .knowledge_sources() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_sources_source_success() { + let client = support::rest_client(None).await; + let result = client.v1().knowledge_sources().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/knowledge_sources/{source}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_sources_source_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .knowledge_sources() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_sources_source_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .knowledge_sources() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_sources_source_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .knowledge_sources() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_knowledge_sources_source_success() { + let client = support::rest_client(None).await; + let body: PatchApiV1KnowledgeSourcesSourceInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client + .v1() + .knowledge_sources() + .update("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "PATCH /api/v1/knowledge_sources/{source}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_knowledge_sources_source_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PatchApiV1KnowledgeSourcesSourceInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_sources() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_knowledge_sources_source_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PatchApiV1KnowledgeSourcesSourceInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_sources() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_knowledge_sources_source_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PatchApiV1KnowledgeSourcesSourceInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_sources() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_knowledge_sources_source_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PatchApiV1KnowledgeSourcesSourceInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_sources() + .update("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_knowledge_sources_source_ingest_success() { + let client = support::rest_client(None).await; + let body: PostApiV1KnowledgeSourcesSourceIngestInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client + .v1() + .knowledge_sources() + .ingest("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/knowledge_sources/{source}/ingest", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_knowledge_sources_source_ingest_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1KnowledgeSourcesSourceIngestInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_sources() + .ingest("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_knowledge_sources_source_ingest_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1KnowledgeSourcesSourceIngestInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_sources() + .ingest("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_knowledge_sources_source_ingest_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1KnowledgeSourcesSourceIngestInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_sources() + .ingest("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_knowledge_sources_source_ingest_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1KnowledgeSourcesSourceIngestInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_sources() + .ingest("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_knowledge_sources_source_ingest_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostApiV1KnowledgeSourcesSourceIngestInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .knowledge_sources() + .ingest("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_sources_kinds_success() { + let client = support::rest_client(None).await; + let result = client.v1().knowledge_sources().kinds().list().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/knowledge_sources/kinds", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_sources_kinds_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .knowledge_sources() + .kinds() + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_knowledge_sources_kinds_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .knowledge_sources() + .kinds() + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_kv_success() { + let client = support::rest_client(None).await; + let params: GetApiV1KvParams = serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().kv().list(Some(¶ms)).await; + assert!(result.is_ok(), "{}: {:?}", "GET /api/v1/kv", result.err()); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_kv_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1KvParams = serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .kv() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_kv_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1KvParams = serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .kv() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_kv_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1KvParams = serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .kv() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_kv_success() { + let client = support::rest_client(None).await; + let body: PostApiV1KvInput = + serde_json::from_str(r#"{"key":"string","value":"string"}"#).expect("valid generated body"); + let result = client.v1().kv().create(&body).await; + assert!(result.is_ok(), "{}: {:?}", "POST /api/v1/kv", result.err()); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_kv_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1KvInput = + serde_json::from_str(r#"{"key":"string","value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .kv() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_kv_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1KvInput = + serde_json::from_str(r#"{"key":"string","value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .kv() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_kv_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1KvInput = + serde_json::from_str(r#"{"key":"string","value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .kv() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_kv_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1KvInput = + serde_json::from_str(r#"{"key":"string","value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .kv() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_kv_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1KvInput = + serde_json::from_str(r#"{"key":"string","value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .kv() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_kv_key_success() { + let client = support::rest_client(None).await; + let result = client.v1().kv().delete("test-key").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/kv/{key}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_kv_key_error_400() { + let client = support::rest_client(Some(400)).await; + let error = client + .v1() + .kv() + .delete("test-key") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_kv_key_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .kv() + .delete("test-key") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_kv_key_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .kv() + .delete("test-key") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_kv_key_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .kv() + .delete("test-key") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_kv_key_success() { + let client = support::rest_client(None).await; + let params: GetApiV1KvKeyParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().kv().get("test-key", Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/kv/{key}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_kv_key_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1KvKeyParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .kv() + .get("test-key", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_kv_key_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1KvKeyParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .kv() + .get("test-key", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_kv_key_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1KvKeyParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .kv() + .get("test-key", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_kv_key_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1KvKeyParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .kv() + .get("test-key", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_kv_key_success() { + let client = support::rest_client(None).await; + let body: PutApiV1KvKeyInput = + serde_json::from_str(r#"{"value":"string"}"#).expect("valid generated body"); + let result = client.v1().kv().upsert("test-key", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "PUT /api/v1/kv/{key}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_kv_key_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PutApiV1KvKeyInput = + serde_json::from_str(r#"{"value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .kv() + .upsert("test-key", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_kv_key_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PutApiV1KvKeyInput = + serde_json::from_str(r#"{"value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .kv() + .upsert("test-key", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_kv_key_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PutApiV1KvKeyInput = + serde_json::from_str(r#"{"value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .kv() + .upsert("test-key", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_kv_key_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PutApiV1KvKeyInput = + serde_json::from_str(r#"{"value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .kv() + .upsert("test-key", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_kv_key_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PutApiV1KvKeyInput = + serde_json::from_str(r#"{"value":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .kv() + .upsert("test-key", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_notification_preferences_success() { + let client = support::rest_client(None).await; + let result = client.v1().notification_preferences().remove().await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/notification_preferences", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_notification_preferences_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .notification_preferences() + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_notification_preferences_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .notification_preferences() + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_notification_preferences_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .notification_preferences() + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_notification_preferences_success() { + let client = support::rest_client(None).await; + let result = client.v1().notification_preferences().list().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/notification_preferences", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_notification_preferences_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .notification_preferences() + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_notification_preferences_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .notification_preferences() + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_notification_preferences_success() { + let client = support::rest_client(None).await; + let body: PutApiV1NotificationPreferencesInput = + serde_json::from_str(r#"{"channel":"string","enabled":true,"type":"string"}"#) + .expect("valid generated body"); + let result = client.v1().notification_preferences().replace(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "PUT /api/v1/notification_preferences", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_notification_preferences_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PutApiV1NotificationPreferencesInput = + serde_json::from_str(r#"{"channel":"string","enabled":true,"type":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .notification_preferences() + .replace(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_notification_preferences_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PutApiV1NotificationPreferencesInput = + serde_json::from_str(r#"{"channel":"string","enabled":true,"type":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .notification_preferences() + .replace(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_notification_preferences_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PutApiV1NotificationPreferencesInput = + serde_json::from_str(r#"{"channel":"string","enabled":true,"type":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .notification_preferences() + .replace(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_notifications_success() { + let client = support::rest_client(None).await; + let params: GetApiV1NotificationsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().notifications().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/notifications", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_notifications_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1NotificationsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .notifications() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_notifications_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1NotificationsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .notifications() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_notifications_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1NotificationsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .notifications() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_read_all_success() { + let client = support::rest_client(None).await; + let result = client.v1().notifications().read_all().await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/notifications/read_all", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_read_all_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .notifications() + .read_all() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_read_all_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .notifications() + .read_all() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_send_success() { + let client = support::rest_client(None).await; + let body: PostApiV1NotificationsSendInput = + serde_json::from_str(r#"{"type":"string","user":"string"}"#).expect("valid generated body"); + let result = client.v1().notifications().send(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/notifications/send", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_send_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1NotificationsSendInput = + serde_json::from_str(r#"{"type":"string","user":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .notifications() + .send(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_send_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1NotificationsSendInput = + serde_json::from_str(r#"{"type":"string","user":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .notifications() + .send(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_send_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1NotificationsSendInput = + serde_json::from_str(r#"{"type":"string","user":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .notifications() + .send(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_send_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1NotificationsSendInput = + serde_json::from_str(r#"{"type":"string","user":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .notifications() + .send(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_send_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1NotificationsSendInput = + serde_json::from_str(r#"{"type":"string","user":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .notifications() + .send(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_notifications_unread_count_success() { + let client = support::rest_client(None).await; + let result = client.v1().notifications().unread_count().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/notifications/unread_count", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_notifications_unread_count_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .notifications() + .unread_count() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_notifications_unread_count_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .notifications() + .unread_count() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_notification_archive_success() { + let client = support::rest_client(None).await; + let result = client.v1().notifications().archive("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/notifications/{notification}/archive", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_notification_archive_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .notifications() + .archive("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_notification_archive_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .notifications() + .archive("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_notification_archive_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .notifications() + .archive("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_notification_read_success() { + let client = support::rest_client(None).await; + let result = client.v1().notifications().read("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/notifications/{notification}/read", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_notification_read_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .notifications() + .read("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_notification_read_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .notifications() + .read("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_notification_read_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .notifications() + .read("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_notification_unarchive_success() { + let client = support::rest_client(None).await; + let result = client.v1().notifications().unarchive("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/notifications/{notification}/unarchive", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_notification_unarchive_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .notifications() + .unarchive("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_notification_unarchive_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .notifications() + .unarchive("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_notifications_notification_unarchive_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .notifications() + .unarchive("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_orgs_success() { + let client = support::rest_client(None).await; + let params: GetApiV1OrgsParams = serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().orgs().list(Some(¶ms)).await; + assert!(result.is_ok(), "{}: {:?}", "GET /api/v1/orgs", result.err()); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_orgs_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1OrgsParams = serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .orgs() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_orgs_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1OrgsParams = serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .orgs() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_definitions_app_id_private_service_id_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .private_service_definitions() + .get("test-id", "test-id") + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/private_service_definitions/{app_id}/{private_service_id}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_definitions_app_id_private_service_id_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .private_service_definitions() + .get("test-id", "test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_definitions_app_id_private_service_id_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .private_service_definitions() + .get("test-id", "test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_definitions_app_id_private_service_id_error_503() { + let client = support::rest_client(Some(503)).await; + let error = client + .v1() + .private_service_definitions() + .get("test-id", "test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 503); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_enrollments_success() { + let client = support::rest_client(None).await; + let params: GetApiV1PrivateServiceEnrollmentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .private_service_enrollments() + .list(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/private_service_enrollments", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_enrollments_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1PrivateServiceEnrollmentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_service_enrollments() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_enrollments_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1PrivateServiceEnrollmentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_service_enrollments() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_enrollments_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1PrivateServiceEnrollmentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_service_enrollments() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_enrollments_error_503() { + let client = support::rest_client(Some(503)).await; + let params: GetApiV1PrivateServiceEnrollmentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_service_enrollments() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 503); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_private_service_enrollments_success() { + let client = support::rest_client(None).await; + let body: PostApiV1PrivateServiceEnrollmentsInput = + serde_json::from_str(r#"{"private_service":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .private_service_enrollments() + .create(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/private_service_enrollments", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_private_service_enrollments_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1PrivateServiceEnrollmentsInput = + serde_json::from_str(r#"{"private_service":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .private_service_enrollments() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_private_service_enrollments_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1PrivateServiceEnrollmentsInput = + serde_json::from_str(r#"{"private_service":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .private_service_enrollments() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_private_service_enrollments_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1PrivateServiceEnrollmentsInput = + serde_json::from_str(r#"{"private_service":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .private_service_enrollments() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_private_service_enrollments_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1PrivateServiceEnrollmentsInput = + serde_json::from_str(r#"{"private_service":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .private_service_enrollments() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_private_service_enrollments_error_503() { + let client = support::rest_client(Some(503)).await; + let body: PostApiV1PrivateServiceEnrollmentsInput = + serde_json::from_str(r#"{"private_service":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .private_service_enrollments() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 503); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_enrollments_private_service_enrollment_id_success() { + let client = support::rest_client(None).await; + let params: GetApiV1PrivateServiceEnrollmentsPrivateServiceEnrollmentIdParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .private_service_enrollments() + .get("test-id", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/private_service_enrollments/{private_service_enrollment_id}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_enrollments_private_service_enrollment_id_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1PrivateServiceEnrollmentsPrivateServiceEnrollmentIdParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_service_enrollments() + .get("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_enrollments_private_service_enrollment_id_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1PrivateServiceEnrollmentsPrivateServiceEnrollmentIdParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_service_enrollments() + .get("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_enrollments_private_service_enrollment_id_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1PrivateServiceEnrollmentsPrivateServiceEnrollmentIdParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_service_enrollments() + .get("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_service_enrollments_private_service_enrollment_id_error_503() { + let client = support::rest_client(Some(503)).await; + let params: GetApiV1PrivateServiceEnrollmentsPrivateServiceEnrollmentIdParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_service_enrollments() + .get("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 503); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_services_success() { + let client = support::rest_client(None).await; + let params: GetApiV1PrivateServicesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().private_services().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/private_services", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_services_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1PrivateServicesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_services() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_services_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1PrivateServicesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_services() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_services_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1PrivateServicesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_services() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_services_error_503() { + let client = support::rest_client(Some(503)).await; + let params: GetApiV1PrivateServicesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_services() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 503); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_private_services_success() { + let client = support::rest_client(None).await; + let body: PostApiV1PrivateServicesInput = serde_json::from_str(r#"{"functions":[{"description":"An example description.","input_schema":{},"name":"Example Name","output_schema":{}}]}"#).expect("valid generated body"); + let result = client.v1().private_services().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/private_services", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_private_services_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1PrivateServicesInput = serde_json::from_str(r#"{"functions":[{"description":"An example description.","input_schema":{},"name":"Example Name","output_schema":{}}]}"#).expect("valid generated body"); + let error = client + .v1() + .private_services() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_private_services_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1PrivateServicesInput = serde_json::from_str(r#"{"functions":[{"description":"An example description.","input_schema":{},"name":"Example Name","output_schema":{}}]}"#).expect("valid generated body"); + let error = client + .v1() + .private_services() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_private_services_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1PrivateServicesInput = serde_json::from_str(r#"{"functions":[{"description":"An example description.","input_schema":{},"name":"Example Name","output_schema":{}}]}"#).expect("valid generated body"); + let error = client + .v1() + .private_services() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_private_services_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1PrivateServicesInput = serde_json::from_str(r#"{"functions":[{"description":"An example description.","input_schema":{},"name":"Example Name","output_schema":{}}]}"#).expect("valid generated body"); + let error = client + .v1() + .private_services() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_private_services_error_503() { + let client = support::rest_client(Some(503)).await; + let body: PostApiV1PrivateServicesInput = serde_json::from_str(r#"{"functions":[{"description":"An example description.","input_schema":{},"name":"Example Name","output_schema":{}}]}"#).expect("valid generated body"); + let error = client + .v1() + .private_services() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 503); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_services_private_service_id_success() { + let client = support::rest_client(None).await; + let params: GetApiV1PrivateServicesPrivateServiceIdParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .private_services() + .get("test-id", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/private_services/{private_service_id}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_services_private_service_id_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1PrivateServicesPrivateServiceIdParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_services() + .get("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_services_private_service_id_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1PrivateServicesPrivateServiceIdParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_services() + .get("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_services_private_service_id_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1PrivateServicesPrivateServiceIdParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_services() + .get("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_private_services_private_service_id_error_503() { + let client = support::rest_client(Some(503)).await; + let params: GetApiV1PrivateServicesPrivateServiceIdParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .private_services() + .get("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 503); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_sandboxes_success() { + let client = support::rest_client(None).await; + let body: PostApiV1SandboxesInput = + serde_json::from_str(r#"{"name":"Example Name","slug":"example-slug"}"#) + .expect("valid generated body"); + let result = client.v1().sandboxes().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/sandboxes", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_sandboxes_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1SandboxesInput = + serde_json::from_str(r#"{"name":"Example Name","slug":"example-slug"}"#) + .expect("valid generated body"); + let error = client + .v1() + .sandboxes() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_sandboxes_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1SandboxesInput = + serde_json::from_str(r#"{"name":"Example Name","slug":"example-slug"}"#) + .expect("valid generated body"); + let error = client + .v1() + .sandboxes() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_sandboxes_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1SandboxesInput = + serde_json::from_str(r#"{"name":"Example Name","slug":"example-slug"}"#) + .expect("valid generated body"); + let error = client + .v1() + .sandboxes() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_sandboxes_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1SandboxesInput = + serde_json::from_str(r#"{"name":"Example Name","slug":"example-slug"}"#) + .expect("valid generated body"); + let error = client + .v1() + .sandboxes() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_sandboxes_sandbox_success() { + let client = support::rest_client(None).await; + let result = client.v1().sandboxes().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/sandboxes/{sandbox}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_sandboxes_sandbox_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .sandboxes() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_sandboxes_sandbox_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .sandboxes() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_sandboxes_sandbox_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .sandboxes() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_sandboxes_sandbox_success() { + let client = support::rest_client(None).await; + let result = client.v1().sandboxes().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/sandboxes/{sandbox}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_sandboxes_sandbox_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .sandboxes() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_sandboxes_sandbox_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .sandboxes() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_sandboxes_sandbox_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .sandboxes() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_sandboxes_sandbox_keys_success() { + let client = support::rest_client(None).await; + let body: PostApiV1SandboxesSandboxKeysInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().sandboxes().keys("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/sandboxes/{sandbox}/keys", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_sandboxes_sandbox_keys_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1SandboxesSandboxKeysInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .sandboxes() + .keys("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_sandboxes_sandbox_keys_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1SandboxesSandboxKeysInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .sandboxes() + .keys("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_sandboxes_sandbox_keys_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1SandboxesSandboxKeysInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .sandboxes() + .keys("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_sandboxes_sandbox_keys_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1SandboxesSandboxKeysInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .sandboxes() + .keys("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_success() { + let client = support::rest_client(None).await; + let params: GetApiV1SlackChannelBindingsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .slack_channel_bindings() + .list(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/slack_channel_bindings", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1SlackChannelBindingsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .slack_channel_bindings() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1SlackChannelBindingsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .slack_channel_bindings() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1SlackChannelBindingsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .slack_channel_bindings() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_success() { + let client = support::rest_client(None).await; + let body: PostApiV1SlackChannelBindingsInput = serde_json::from_str(r#"{"agent_user_ids":["string"],"channel_id":"string","slack_team_id":"string","team_id":"string"}"#).expect("valid generated body"); + let result = client.v1().slack_channel_bindings().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/slack_channel_bindings", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1SlackChannelBindingsInput = serde_json::from_str(r#"{"agent_user_ids":["string"],"channel_id":"string","slack_team_id":"string","team_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1SlackChannelBindingsInput = serde_json::from_str(r#"{"agent_user_ids":["string"],"channel_id":"string","slack_team_id":"string","team_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1SlackChannelBindingsInput = serde_json::from_str(r#"{"agent_user_ids":["string"],"channel_id":"string","slack_team_id":"string","team_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1SlackChannelBindingsInput = serde_json::from_str(r#"{"agent_user_ids":["string"],"channel_id":"string","slack_team_id":"string","team_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1SlackChannelBindingsInput = serde_json::from_str(r#"{"agent_user_ids":["string"],"channel_id":"string","slack_team_id":"string","team_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1SlackChannelBindingsInput = serde_json::from_str(r#"{"agent_user_ids":["string"],"channel_id":"string","slack_team_id":"string","team_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_provision_success() { + let client = support::rest_client(None).await; + let body: PostApiV1SlackChannelBindingsProvisionInput = serde_json::from_str(r#"{"customer_key":"string","customer_label":"string","slack_team_id":"string","template_config_id":"string"}"#).expect("valid generated body"); + let result = client.v1().slack_channel_bindings().provision(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/slack_channel_bindings/provision", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_provision_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1SlackChannelBindingsProvisionInput = serde_json::from_str(r#"{"customer_key":"string","customer_label":"string","slack_team_id":"string","template_config_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .provision(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_provision_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1SlackChannelBindingsProvisionInput = serde_json::from_str(r#"{"customer_key":"string","customer_label":"string","slack_team_id":"string","template_config_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .provision(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_provision_error_402() { + let client = support::rest_client(Some(402)).await; + let body: PostApiV1SlackChannelBindingsProvisionInput = serde_json::from_str(r#"{"customer_key":"string","customer_label":"string","slack_team_id":"string","template_config_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .provision(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 402); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_provision_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1SlackChannelBindingsProvisionInput = serde_json::from_str(r#"{"customer_key":"string","customer_label":"string","slack_team_id":"string","template_config_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .provision(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_provision_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1SlackChannelBindingsProvisionInput = serde_json::from_str(r#"{"customer_key":"string","customer_label":"string","slack_team_id":"string","template_config_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .provision(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_provision_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1SlackChannelBindingsProvisionInput = serde_json::from_str(r#"{"customer_key":"string","customer_label":"string","slack_team_id":"string","template_config_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .provision(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_provision_error_500() { + let client = support::rest_client(Some(500)).await; + let body: PostApiV1SlackChannelBindingsProvisionInput = serde_json::from_str(r#"{"customer_key":"string","customer_label":"string","slack_team_id":"string","template_config_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .provision(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 500); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_provision_error_502() { + let client = support::rest_client(Some(502)).await; + let body: PostApiV1SlackChannelBindingsProvisionInput = serde_json::from_str(r#"{"customer_key":"string","customer_label":"string","slack_team_id":"string","template_config_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .provision(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 502); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_slack_channel_bindings_channel_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .slack_channel_bindings() + .delete("test-value") + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/slack_channel_bindings/{channel}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_slack_channel_bindings_channel_error_400() { + let client = support::rest_client(Some(400)).await; + let error = client + .v1() + .slack_channel_bindings() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_slack_channel_bindings_channel_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .slack_channel_bindings() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_slack_channel_bindings_channel_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .slack_channel_bindings() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_slack_channel_bindings_channel_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .slack_channel_bindings() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_slack_channel_bindings_channel_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .slack_channel_bindings() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_channel_success() { + let client = support::rest_client(None).await; + let params: GetApiV1SlackChannelBindingsChannelParams = + serde_json::from_str(r#"{"slack_team_id":"string"}"#).expect("valid generated params"); + let result = client + .v1() + .slack_channel_bindings() + .get("test-value", ¶ms) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/slack_channel_bindings/{channel}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_channel_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1SlackChannelBindingsChannelParams = + serde_json::from_str(r#"{"slack_team_id":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .slack_channel_bindings() + .get("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_channel_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1SlackChannelBindingsChannelParams = + serde_json::from_str(r#"{"slack_team_id":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .slack_channel_bindings() + .get("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_channel_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1SlackChannelBindingsChannelParams = + serde_json::from_str(r#"{"slack_team_id":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .slack_channel_bindings() + .get("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_channel_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1SlackChannelBindingsChannelParams = + serde_json::from_str(r#"{"slack_team_id":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .slack_channel_bindings() + .get("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_channel_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1SlackChannelBindingsChannelParams = + serde_json::from_str(r#"{"slack_team_id":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .slack_channel_bindings() + .get("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_channel_delivery_outcomes_success() { + let client = support::rest_client(None).await; + let params: GetApiV1SlackChannelBindingsChannelDeliveryOutcomesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .slack_channel_bindings() + .delivery_outcomes("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/slack_channel_bindings/{channel}/delivery_outcomes", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_channel_delivery_outcomes_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1SlackChannelBindingsChannelDeliveryOutcomesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .slack_channel_bindings() + .delivery_outcomes("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_channel_delivery_outcomes_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1SlackChannelBindingsChannelDeliveryOutcomesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .slack_channel_bindings() + .delivery_outcomes("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_channel_delivery_outcomes_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1SlackChannelBindingsChannelDeliveryOutcomesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .slack_channel_bindings() + .delivery_outcomes("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_slack_channel_bindings_channel_delivery_outcomes_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1SlackChannelBindingsChannelDeliveryOutcomesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .slack_channel_bindings() + .delivery_outcomes("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_channel_deposit_thread_success() { + let client = support::rest_client(None).await; + let body: PostApiV1SlackChannelBindingsChannelDepositThreadInput = + serde_json::from_str(r#"{"slack_team_id":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .slack_channel_bindings() + .deposit_thread("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/slack_channel_bindings/{channel}/deposit_thread", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_channel_deposit_thread_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1SlackChannelBindingsChannelDepositThreadInput = + serde_json::from_str(r#"{"slack_team_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .deposit_thread("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_channel_deposit_thread_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1SlackChannelBindingsChannelDepositThreadInput = + serde_json::from_str(r#"{"slack_team_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .deposit_thread("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_channel_deposit_thread_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1SlackChannelBindingsChannelDepositThreadInput = + serde_json::from_str(r#"{"slack_team_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .deposit_thread("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_channel_deposit_thread_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1SlackChannelBindingsChannelDepositThreadInput = + serde_json::from_str(r#"{"slack_team_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .deposit_thread("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_slack_channel_bindings_channel_deposit_thread_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1SlackChannelBindingsChannelDepositThreadInput = + serde_json::from_str(r#"{"slack_team_id":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .slack_channel_bindings() + .deposit_thread("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solution_categories_success() { + let client = support::rest_client(None).await; + let params: GetApiV1SolutionCategoriesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().solution_categories().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/solution_categories", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solution_categories_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1SolutionCategoriesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .solution_categories() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solution_categories_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1SolutionCategoriesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .solution_categories() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solution_instances_success() { + let client = support::rest_client(None).await; + let params: GetApiV1SolutionInstancesParams = + serde_json::from_str(r#"{"solution_template_config_id":"string"}"#) + .expect("valid generated params"); + let result = client.v1().solution_instances().list(¶ms).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/solution_instances", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solution_instances_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1SolutionInstancesParams = + serde_json::from_str(r#"{"solution_template_config_id":"string"}"#) + .expect("valid generated params"); + let error = client + .v1() + .solution_instances() + .list(¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solution_instances_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1SolutionInstancesParams = + serde_json::from_str(r#"{"solution_template_config_id":"string"}"#) + .expect("valid generated params"); + let error = client + .v1() + .solution_instances() + .list(¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solution_instances_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1SolutionInstancesParams = + serde_json::from_str(r#"{"solution_template_config_id":"string"}"#) + .expect("valid generated params"); + let error = client + .v1() + .solution_instances() + .list(¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solution_tags_success() { + let client = support::rest_client(None).await; + let params: GetApiV1SolutionTagsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().solution_tags().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/solution_tags", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solution_tags_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1SolutionTagsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .solution_tags() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solution_tags_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1SolutionTagsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .solution_tags() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_success() { + let client = support::rest_client(None).await; + let params: GetApiV1SolutionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().solutions().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/solutions", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1SolutionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .solutions() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1SolutionsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .solutions() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_success() { + let client = support::rest_client(None).await; + let body: PostApiV1SolutionsInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().solutions().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/solutions", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1SolutionsInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1SolutionsInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1SolutionsInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1SolutionsInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1SolutionsInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1SolutionsInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_solutions_solution_success() { + let client = support::rest_client(None).await; + let result = client.v1().solutions().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/solutions/{solution}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_solutions_solution_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .solutions() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_solutions_solution_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .solutions() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_solutions_solution_error_500() { + let client = support::rest_client(Some(500)).await; + let error = client + .v1() + .solutions() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 500); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_solution_success() { + let client = support::rest_client(None).await; + let result = client.v1().solutions().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/solutions/{solution}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_solution_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .solutions() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_solution_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .solutions() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_solution_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .solutions() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_solution_dependents_success() { + let client = support::rest_client(None).await; + let result = client.v1().solutions().dependents("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/solutions/{solution}/dependents", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_solution_dependents_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .solutions() + .dependents("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_solution_dependents_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .solutions() + .dependents("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_solution_image_success() { + let client = support::rest_client(None).await; + let params: GetApiV1SolutionsSolutionImageParams = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated params"); + let result = client.v1().solutions().image("test-value", ¶ms).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/solutions/{solution}/image", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_solution_image_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1SolutionsSolutionImageParams = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .solutions() + .image("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_install_success() { + let client = support::rest_client(None).await; + let body: PostApiV1SolutionsSolutionInstallInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().solutions().install("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/solutions/{solution}/install", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_install_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1SolutionsSolutionInstallInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .install("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_install_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1SolutionsSolutionInstallInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .install("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_install_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1SolutionsSolutionInstallInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .install("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_install_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1SolutionsSolutionInstallInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .install("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_install_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1SolutionsSolutionInstallInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .install("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_install_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1SolutionsSolutionInstallInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .install("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_solution_readme_success() { + let client = support::rest_client(None).await; + let params: GetApiV1SolutionsSolutionReadmeParams = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated params"); + let result = client.v1().solutions().readme("test-value", ¶ms).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/solutions/{solution}/readme", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_solution_readme_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1SolutionsSolutionReadmeParams = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .solutions() + .readme("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_solutions_solution_readme_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1SolutionsSolutionReadmeParams = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .solutions() + .readme("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_upgrade_success() { + let client = support::rest_client(None).await; + let body: PostApiV1SolutionsSolutionUpgradeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().solutions().upgrade("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/solutions/{solution}/upgrade", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_upgrade_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1SolutionsSolutionUpgradeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .upgrade("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_upgrade_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1SolutionsSolutionUpgradeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .upgrade("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_upgrade_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1SolutionsSolutionUpgradeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .upgrade("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_upgrade_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1SolutionsSolutionUpgradeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .upgrade("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_upgrade_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1SolutionsSolutionUpgradeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .upgrade("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_view_success() { + let client = support::rest_client(None).await; + let body: PostApiV1SolutionsSolutionViewInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().solutions().view("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/solutions/{solution}/view", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_view_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1SolutionsSolutionViewInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .view("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_view_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1SolutionsSolutionViewInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .view("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_solutions_solution_view_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1SolutionsSolutionViewInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .solutions() + .view("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_status_ping_success() { + let client = support::rest_client(None).await; + let result = client.v1().status().ping().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/status/ping", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_success() { + let client = support::rest_client(None).await; + let result = client.v1().tasks().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/tasks/{task}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .tasks() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .tasks() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .tasks() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TasksTaskParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().tasks().get("test-value", Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/tasks/{task}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TasksTaskParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .get("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TasksTaskParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .get("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1TasksTaskParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .get("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_tasks_task_success() { + let client = support::rest_client(None).await; + let body: PutApiV1TasksTaskInput = serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().tasks().replace("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "PUT /api/v1/tasks/{task}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_tasks_task_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PutApiV1TasksTaskInput = serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_tasks_task_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PutApiV1TasksTaskInput = serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_tasks_task_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PutApiV1TasksTaskInput = serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_tasks_task_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PutApiV1TasksTaskInput = serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_tasks_task_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PutApiV1TasksTaskInput = serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_activity_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TasksTaskActivityParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .tasks() + .activity("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/tasks/{task}/activity", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_activity_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TasksTaskActivityParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .activity("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_activity_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TasksTaskActivityParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .activity("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_activity_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1TasksTaskActivityParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .activity("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_blocking_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TasksTaskBlockingParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .tasks() + .blocking("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/tasks/{task}/blocking", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_blocking_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TasksTaskBlockingParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .blocking("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_blocking_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TasksTaskBlockingParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .blocking("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_blocking_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1TasksTaskBlockingParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .blocking("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_subtasks_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TasksTaskSubtasksParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .tasks() + .subtasks("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/tasks/{task}/subtasks", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_subtasks_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TasksTaskSubtasksParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .subtasks("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_subtasks_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TasksTaskSubtasksParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .subtasks("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_subtasks_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1TasksTaskSubtasksParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .subtasks("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_blockers_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TasksTaskBlockersParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .tasks() + .blockers("test-value") + .list(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/tasks/{task}/blockers", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_blockers_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TasksTaskBlockersParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .blockers("test-value") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_blockers_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TasksTaskBlockersParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .blockers("test-value") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_blockers_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1TasksTaskBlockersParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .blockers("test-value") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_blockers_success() { + let client = support::rest_client(None).await; + let body: PostApiV1TasksTaskBlockersInput = + serde_json::from_str(r#"{"blocker":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .tasks() + .blockers("test-value") + .create(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/tasks/{task}/blockers", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_blockers_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1TasksTaskBlockersInput = + serde_json::from_str(r#"{"blocker":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .blockers("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_blockers_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1TasksTaskBlockersInput = + serde_json::from_str(r#"{"blocker":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .blockers("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_blockers_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1TasksTaskBlockersInput = + serde_json::from_str(r#"{"blocker":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .blockers("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_blockers_blocker_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .tasks() + .blockers("test-value") + .delete("test-value") + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/tasks/{task}/blockers/{blocker}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_blockers_blocker_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .tasks() + .blockers("test-value") + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_blockers_blocker_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .tasks() + .blockers("test-value") + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_blockers_blocker_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .tasks() + .blockers("test-value") + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_comments_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TasksTaskCommentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .tasks() + .comments("test-value") + .list(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/tasks/{task}/comments", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_comments_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TasksTaskCommentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .comments("test-value") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_comments_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TasksTaskCommentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .comments("test-value") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_comments_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1TasksTaskCommentsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .tasks() + .comments("test-value") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_comments_success() { + let client = support::rest_client(None).await; + let body: PostApiV1TasksTaskCommentsInput = + serde_json::from_str(r#"{"comment":{"body":"Looks good to me, ready for review."}}"#) + .expect("valid generated body"); + let result = client + .v1() + .tasks() + .comments("test-value") + .create(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/tasks/{task}/comments", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_comments_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1TasksTaskCommentsInput = + serde_json::from_str(r#"{"comment":{"body":"Looks good to me, ready for review."}}"#) + .expect("valid generated body"); + let error = client + .v1() + .tasks() + .comments("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_comments_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1TasksTaskCommentsInput = + serde_json::from_str(r#"{"comment":{"body":"Looks good to me, ready for review."}}"#) + .expect("valid generated body"); + let error = client + .v1() + .tasks() + .comments("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_comments_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1TasksTaskCommentsInput = + serde_json::from_str(r#"{"comment":{"body":"Looks good to me, ready for review."}}"#) + .expect("valid generated body"); + let error = client + .v1() + .tasks() + .comments("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_comments_comment_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .tasks() + .comments("test-value") + .delete("test-value") + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/tasks/{task}/comments/{comment}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_comments_comment_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .tasks() + .comments("test-value") + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_comments_comment_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .tasks() + .comments("test-value") + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_comments_comment_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .tasks() + .comments("test-value") + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_comments_comment_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .tasks() + .comments("test-value") + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_tasks_task_comments_comment_success() { + let client = support::rest_client(None).await; + let body: PutApiV1TasksTaskCommentsCommentInput = + serde_json::from_str(r#"{"body":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .tasks() + .comments("test-value") + .replace("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "PUT /api/v1/tasks/{task}/comments/{comment}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_tasks_task_comments_comment_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PutApiV1TasksTaskCommentsCommentInput = + serde_json::from_str(r#"{"body":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .comments("test-value") + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_tasks_task_comments_comment_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PutApiV1TasksTaskCommentsCommentInput = + serde_json::from_str(r#"{"body":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .comments("test-value") + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_tasks_task_comments_comment_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PutApiV1TasksTaskCommentsCommentInput = + serde_json::from_str(r#"{"body":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .comments("test-value") + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_tasks_task_comments_comment_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PutApiV1TasksTaskCommentsCommentInput = + serde_json::from_str(r#"{"body":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .comments("test-value") + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_lease_success() { + let client = support::rest_client(None).await; + let result = client.v1().tasks().lease("test-value").remove().await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/tasks/{task}/lease", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_lease_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .tasks() + .lease("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_lease_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .tasks() + .lease("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_lease_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .tasks() + .lease("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_lease_error_409() { + let client = support::rest_client(Some(409)).await; + let error = client + .v1() + .tasks() + .lease("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_lease_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .tasks() + .lease("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_lease_success() { + let client = support::rest_client(None).await; + let result = client.v1().tasks().lease("test-value").list().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/tasks/{task}/lease", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_lease_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .tasks() + .lease("test-value") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_lease_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .tasks() + .lease("test-value") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_lease_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .tasks() + .lease("test-value") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_tasks_task_lease_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .tasks() + .lease("test-value") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_lease_success() { + let client = support::rest_client(None).await; + let body: PostApiV1TasksTaskLeaseInput = serde_json::from_str(r#"{"harness":"string","lease_id":"string","session_id":"string","session_name":"Example Name"}"#).expect("valid generated body"); + let result = client.v1().tasks().lease("test-value").create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/tasks/{task}/lease", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_lease_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1TasksTaskLeaseInput = serde_json::from_str(r#"{"harness":"string","lease_id":"string","session_id":"string","session_name":"Example Name"}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .lease("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_lease_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1TasksTaskLeaseInput = serde_json::from_str(r#"{"harness":"string","lease_id":"string","session_id":"string","session_name":"Example Name"}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .lease("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_lease_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1TasksTaskLeaseInput = serde_json::from_str(r#"{"harness":"string","lease_id":"string","session_id":"string","session_name":"Example Name"}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .lease("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_lease_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1TasksTaskLeaseInput = serde_json::from_str(r#"{"harness":"string","lease_id":"string","session_id":"string","session_name":"Example Name"}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .lease("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_lease_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1TasksTaskLeaseInput = serde_json::from_str(r#"{"harness":"string","lease_id":"string","session_id":"string","session_name":"Example Name"}"#).expect("valid generated body"); + let error = client + .v1() + .tasks() + .lease("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_lease_renew_success() { + let client = support::rest_client(None).await; + let body: PostApiV1TasksTaskLeaseRenewInput = + serde_json::from_str(r#"{"lease_id":"string","session_id":"string"}"#) + .expect("valid generated body"); + let result = client.v1().tasks().lease("test-value").renew(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/tasks/{task}/lease/renew", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_lease_renew_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1TasksTaskLeaseRenewInput = + serde_json::from_str(r#"{"lease_id":"string","session_id":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .tasks() + .lease("test-value") + .renew(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_lease_renew_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1TasksTaskLeaseRenewInput = + serde_json::from_str(r#"{"lease_id":"string","session_id":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .tasks() + .lease("test-value") + .renew(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_lease_renew_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1TasksTaskLeaseRenewInput = + serde_json::from_str(r#"{"lease_id":"string","session_id":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .tasks() + .lease("test-value") + .renew(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_lease_renew_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1TasksTaskLeaseRenewInput = + serde_json::from_str(r#"{"lease_id":"string","session_id":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .tasks() + .lease("test-value") + .renew(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_lease_renew_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1TasksTaskLeaseRenewInput = + serde_json::from_str(r#"{"lease_id":"string","session_id":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .tasks() + .lease("test-value") + .renew(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_links_success() { + let client = support::rest_client(None).await; + let result = client.v1().tasks().links("test-value").remove().await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/tasks/{task}/links", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_links_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .tasks() + .links("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_links_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .tasks() + .links("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_tasks_task_links_error_502() { + let client = support::rest_client(Some(502)).await; + let error = client + .v1() + .tasks() + .links("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 502); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_links_success() { + let client = support::rest_client(None).await; + let body: PostApiV1TasksTaskLinksInput = serde_json::from_str( + r#"{"external_scope":"string","object_id":"string","object_type":"string"}"#, + ) + .expect("valid generated body"); + let result = client.v1().tasks().links("test-value").create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/tasks/{task}/links", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_links_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1TasksTaskLinksInput = serde_json::from_str( + r#"{"external_scope":"string","object_id":"string","object_type":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .tasks() + .links("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_links_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1TasksTaskLinksInput = serde_json::from_str( + r#"{"external_scope":"string","object_id":"string","object_type":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .tasks() + .links("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_links_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1TasksTaskLinksInput = serde_json::from_str( + r#"{"external_scope":"string","object_id":"string","object_type":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .tasks() + .links("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_tasks_task_links_error_502() { + let client = support::rest_client(Some(502)).await; + let body: PostApiV1TasksTaskLinksInput = serde_json::from_str( + r#"{"external_scope":"string","object_id":"string","object_type":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .tasks() + .links("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 502); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_team_memberships_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TeamMembershipsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().team_memberships().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/team_memberships", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_team_memberships_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TeamMembershipsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .team_memberships() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_team_memberships_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1TeamMembershipsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .team_memberships() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_team_memberships_team_membership_success() { + let client = support::rest_client(None).await; + let result = client.v1().team_memberships().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/team_memberships/{team_membership}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_team_memberships_team_membership_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .team_memberships() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_team_memberships_team_membership_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .team_memberships() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TeamsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().teams().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/teams", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1TeamsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TeamsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1TeamsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_success() { + let client = support::rest_client(None).await; + let body: PostApiV1TeamsInput = + serde_json::from_str(r#"{"name":"Example Name"}"#).expect("valid generated body"); + let result = client.v1().teams().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/teams", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1TeamsInput = + serde_json::from_str(r#"{"name":"Example Name"}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1TeamsInput = + serde_json::from_str(r#"{"name":"Example Name"}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1TeamsInput = + serde_json::from_str(r#"{"name":"Example Name"}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_join_by_code_success() { + let client = support::rest_client(None).await; + let body: PostApiV1TeamsJoinByCodeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().teams().join_by_code(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/teams/join_by_code", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_join_by_code_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1TeamsJoinByCodeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .join_by_code(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_join_by_code_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1TeamsJoinByCodeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .join_by_code(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_join_by_code_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1TeamsJoinByCodeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .join_by_code(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_join_by_code_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostApiV1TeamsJoinByCodeInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .join_by_code(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_success() { + let client = support::rest_client(None).await; + let result = client.v1().teams().delete("test-id").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/teams/{team}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .teams() + .delete("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .teams() + .delete("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .teams() + .delete("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_success() { + let client = support::rest_client(None).await; + let result = client.v1().teams().get("test-id").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/teams/{team}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .teams() + .get("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .teams() + .get("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .teams() + .get("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_teams_team_success() { + let client = support::rest_client(None).await; + let body: PatchApiV1TeamsTeamInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().teams().update("test-id", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "PATCH /api/v1/teams/{team}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_teams_team_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PatchApiV1TeamsTeamInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .update("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_teams_team_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PatchApiV1TeamsTeamInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .update("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_teams_team_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PatchApiV1TeamsTeamInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .update("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_teams_team_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PatchApiV1TeamsTeamInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .update("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_artifacts_success() { + let client = support::rest_client(None).await; + let result = client.v1().teams().artifacts("test-id").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/teams/{team}/artifacts", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_artifacts_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .teams() + .artifacts("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_artifacts_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .teams() + .artifacts("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_invite_success() { + let client = support::rest_client(None).await; + let result = client.v1().teams().invite("test-id").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/teams/{team}/invite", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_invite_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .teams() + .invite("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_invite_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .teams() + .invite("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_invite_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .teams() + .invite("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_invites_success() { + let client = support::rest_client(None).await; + let result = client.v1().teams().invites("test-id").await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/teams/{team}/invites", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_invites_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .teams() + .invites("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_invites_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .teams() + .invites("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_join_success() { + let client = support::rest_client(None).await; + let body: PostApiV1TeamsTeamJoinInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().teams().join("test-id", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/teams/{team}/join", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_join_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1TeamsTeamJoinInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .join("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_join_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1TeamsTeamJoinInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .join("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_join_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1TeamsTeamJoinInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .join("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_join_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1TeamsTeamJoinInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .join("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_leave_success() { + let client = support::rest_client(None).await; + let result = client.v1().teams().leave("test-id").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/teams/{team}/leave", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_leave_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .teams() + .leave("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_leave_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .teams() + .leave("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_leave_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .teams() + .leave("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_leave_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .teams() + .leave("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_task_assignees_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TeamsTeamTaskAssigneesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .teams() + .task_assignees("test-id", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/teams/{team}/task_assignees", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_task_assignees_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TeamsTeamTaskAssigneesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .task_assignees("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_task_assignees_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TeamsTeamTaskAssigneesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .task_assignees("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_task_assignees_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1TeamsTeamTaskAssigneesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .task_assignees("test-id", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_custom_objects_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TeamsTeamCustomObjectsParams = + serde_json::from_str(r#"{"type":"string"}"#).expect("valid generated params"); + let result = client + .v1() + .teams() + .custom_objects("test-id") + .list(¶ms) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/teams/{team}/custom_objects", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_custom_objects_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TeamsTeamCustomObjectsParams = + serde_json::from_str(r#"{"type":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .custom_objects("test-id") + .list(¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_custom_objects_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TeamsTeamCustomObjectsParams = + serde_json::from_str(r#"{"type":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .custom_objects("test-id") + .list(¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_custom_objects_success() { + let client = support::rest_client(None).await; + let body: PostApiV1TeamsTeamCustomObjectsInput = + serde_json::from_str(r#"{"fields":{},"type":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .teams() + .custom_objects("test-id") + .create(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/teams/{team}/custom_objects", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_custom_objects_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1TeamsTeamCustomObjectsInput = + serde_json::from_str(r#"{"fields":{},"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .custom_objects("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_custom_objects_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1TeamsTeamCustomObjectsInput = + serde_json::from_str(r#"{"fields":{},"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .custom_objects("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_custom_objects_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1TeamsTeamCustomObjectsInput = + serde_json::from_str(r#"{"fields":{},"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .custom_objects("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_members_success() { + let client = support::rest_client(None).await; + let result = client.v1().teams().members("test-id").remove().await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/teams/{team}/members", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_members_error_400() { + let client = support::rest_client(Some(400)).await; + let error = client + .v1() + .teams() + .members("test-id") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_members_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .teams() + .members("test-id") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_members_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .teams() + .members("test-id") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_teams_team_members_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .teams() + .members("test-id") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_members_success() { + let client = support::rest_client(None).await; + let result = client.v1().teams().members("test-id").list().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/teams/{team}/members", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_members_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .teams() + .members("test-id") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_members_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .teams() + .members("test-id") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_members_success() { + let client = support::rest_client(None).await; + let body: PostApiV1TeamsTeamMembersInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().teams().members("test-id").create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/teams/{team}/members", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_members_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1TeamsTeamMembersInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .members("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_members_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1TeamsTeamMembersInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .members("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_members_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1TeamsTeamMembersInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .members("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_teams_team_members_user_success() { + let client = support::rest_client(None).await; + let body: PatchApiV1TeamsTeamMembersUserInput = + serde_json::from_str(r#"{"role":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .teams() + .members("test-id") + .update("test-id", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "PATCH /api/v1/teams/{team}/members/{user}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_teams_team_members_user_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PatchApiV1TeamsTeamMembersUserInput = + serde_json::from_str(r#"{"role":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .members("test-id") + .update("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_teams_team_members_user_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PatchApiV1TeamsTeamMembersUserInput = + serde_json::from_str(r#"{"role":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .members("test-id") + .update("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_teams_team_members_user_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PatchApiV1TeamsTeamMembersUserInput = + serde_json::from_str(r#"{"role":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .members("test-id") + .update("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_teams_team_members_user_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PatchApiV1TeamsTeamMembersUserInput = + serde_json::from_str(r#"{"role":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .members("test-id") + .update("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn patch_api_v1_teams_team_members_user_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PatchApiV1TeamsTeamMembersUserInput = + serde_json::from_str(r#"{"role":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .members("test-id") + .update("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TeamsTeamTasksParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .teams() + .tasks("test-id") + .list(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/teams/{team}/tasks", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TeamsTeamTasksParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TeamsTeamTasksParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1TeamsTeamTasksParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_tasks_success() { + let client = support::rest_client(None).await; + let body: PostApiV1TeamsTeamTasksInput = serde_json::from_str(r#"{"task":{"description":"An example description.","due_date":"2024-01-01T00:00:00Z","links":{"key":"value"},"metadata":{"key":"value"},"name":"Example Name","owner_agent":"string","owner_user":"string","parent":"tsk_01j3k5m7n9p2r4s6t8v0w1x2","priority":2,"status":"open","tags":["backend","q3-launch"],"thread":"thr_01j3k5m7n9p2r4s6t8v0w1x2"}}"#).expect("valid generated body"); + let result = client.v1().teams().tasks("test-id").create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/teams/{team}/tasks", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_tasks_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1TeamsTeamTasksInput = serde_json::from_str(r#"{"task":{"description":"An example description.","due_date":"2024-01-01T00:00:00Z","links":{"key":"value"},"metadata":{"key":"value"},"name":"Example Name","owner_agent":"string","owner_user":"string","parent":"tsk_01j3k5m7n9p2r4s6t8v0w1x2","priority":2,"status":"open","tags":["backend","q3-launch"],"thread":"thr_01j3k5m7n9p2r4s6t8v0w1x2"}}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .tasks("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_tasks_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1TeamsTeamTasksInput = serde_json::from_str(r#"{"task":{"description":"An example description.","due_date":"2024-01-01T00:00:00Z","links":{"key":"value"},"metadata":{"key":"value"},"name":"Example Name","owner_agent":"string","owner_user":"string","parent":"tsk_01j3k5m7n9p2r4s6t8v0w1x2","priority":2,"status":"open","tags":["backend","q3-launch"],"thread":"thr_01j3k5m7n9p2r4s6t8v0w1x2"}}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .tasks("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_tasks_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1TeamsTeamTasksInput = serde_json::from_str(r#"{"task":{"description":"An example description.","due_date":"2024-01-01T00:00:00Z","links":{"key":"value"},"metadata":{"key":"value"},"name":"Example Name","owner_agent":"string","owner_user":"string","parent":"tsk_01j3k5m7n9p2r4s6t8v0w1x2","priority":2,"status":"open","tags":["backend","q3-launch"],"thread":"thr_01j3k5m7n9p2r4s6t8v0w1x2"}}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .tasks("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_blocker_cycles_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TeamsTeamTasksBlockerCyclesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .teams() + .tasks("test-id") + .blocker_cycles(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/teams/{team}/tasks/blocker_cycles", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_blocker_cycles_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TeamsTeamTasksBlockerCyclesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .blocker_cycles(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_blocker_cycles_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TeamsTeamTasksBlockerCyclesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .blocker_cycles(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_blocker_cycles_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1TeamsTeamTasksBlockerCyclesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .blocker_cycles(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_metrics_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TeamsTeamTasksMetricsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .teams() + .tasks("test-id") + .metrics(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/teams/{team}/tasks/metrics", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_metrics_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TeamsTeamTasksMetricsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .metrics(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_metrics_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TeamsTeamTasksMetricsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .metrics(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_metrics_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1TeamsTeamTasksMetricsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .metrics(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_ready_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TeamsTeamTasksReadyParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .teams() + .tasks("test-id") + .ready(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/teams/{team}/tasks/ready", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_ready_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TeamsTeamTasksReadyParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .ready(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_ready_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TeamsTeamTasksReadyParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .ready(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_ready_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1TeamsTeamTasksReadyParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .ready(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_search_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TeamsTeamTasksSearchParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .teams() + .tasks("test-id") + .search(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/teams/{team}/tasks/search", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_search_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TeamsTeamTasksSearchParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .search(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_search_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TeamsTeamTasksSearchParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .search(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_tasks_search_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1TeamsTeamTasksSearchParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .tasks("test-id") + .search(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_threads_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TeamsTeamThreadsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .teams() + .threads("test-id") + .list(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/teams/{team}/threads", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_threads_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TeamsTeamThreadsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .threads("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_threads_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TeamsTeamThreadsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .threads("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_threads_success() { + let client = support::rest_client(None).await; + let body: PostApiV1TeamsTeamThreadsInput = serde_json::from_str(r#"{"thread":{"create_legacy_agent":true,"description":"An example description.","is_unlisted":true,"key":"string","members":[{"id":"string","type":"user"}],"metadata":{"key":"value"},"muted":true,"org_id":"string","profile_picture":{"data":"string","filename":"string","mime_type":"application/json"},"settings":{"agent_enabled":true},"slug":"example-slug","title":"Example Title","visibility":"team"}}"#).expect("valid generated body"); + let result = client.v1().teams().threads("test-id").create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/teams/{team}/threads", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_threads_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1TeamsTeamThreadsInput = serde_json::from_str(r#"{"thread":{"create_legacy_agent":true,"description":"An example description.","is_unlisted":true,"key":"string","members":[{"id":"string","type":"user"}],"metadata":{"key":"value"},"muted":true,"org_id":"string","profile_picture":{"data":"string","filename":"string","mime_type":"application/json"},"settings":{"agent_enabled":true},"slug":"example-slug","title":"Example Title","visibility":"team"}}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .threads("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_threads_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1TeamsTeamThreadsInput = serde_json::from_str(r#"{"thread":{"create_legacy_agent":true,"description":"An example description.","is_unlisted":true,"key":"string","members":[{"id":"string","type":"user"}],"metadata":{"key":"value"},"muted":true,"org_id":"string","profile_picture":{"data":"string","filename":"string","mime_type":"application/json"},"settings":{"agent_enabled":true},"slug":"example-slug","title":"Example Title","visibility":"team"}}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .threads("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_teams_team_threads_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1TeamsTeamThreadsInput = serde_json::from_str(r#"{"thread":{"create_legacy_agent":true,"description":"An example description.","is_unlisted":true,"key":"string","members":[{"id":"string","type":"user"}],"metadata":{"key":"value"},"muted":true,"org_id":"string","profile_picture":{"data":"string","filename":"string","mime_type":"application/json"},"settings":{"agent_enabled":true},"slug":"example-slug","title":"Example Title","visibility":"team"}}"#).expect("valid generated body"); + let error = client + .v1() + .teams() + .threads("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_threads_metrics_success() { + let client = support::rest_client(None).await; + let params: GetApiV1TeamsTeamThreadsMetricsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .teams() + .threads("test-id") + .metrics(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/teams/{team}/threads/metrics", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_threads_metrics_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1TeamsTeamThreadsMetricsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .threads("test-id") + .metrics(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_threads_metrics_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1TeamsTeamThreadsMetricsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .threads("test-id") + .metrics(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_teams_team_threads_metrics_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1TeamsTeamThreadsMetricsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .teams() + .threads("test-id") + .metrics(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_thread_messages_message_success() { + let client = support::rest_client(None).await; + let result = client.v1().thread_messages().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/thread_messages/{message}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_thread_messages_message_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .thread_messages() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_thread_messages_message_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .thread_messages() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_thread_messages_message_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .thread_messages() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_thread_messages_message_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .thread_messages() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_thread_messages_message_success() { + let client = support::rest_client(None).await; + let result = client.v1().thread_messages().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/thread_messages/{message}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_thread_messages_message_error_400() { + let client = support::rest_client(Some(400)).await; + let error = client + .v1() + .thread_messages() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_thread_messages_message_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .thread_messages() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_thread_messages_message_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .thread_messages() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_thread_messages_message_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .thread_messages() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_thread_messages_message_success() { + let client = support::rest_client(None).await; + let body: PutApiV1ThreadMessagesMessageInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client + .v1() + .thread_messages() + .replace("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "PUT /api/v1/thread_messages/{message}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_thread_messages_message_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PutApiV1ThreadMessagesMessageInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .thread_messages() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_thread_messages_message_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PutApiV1ThreadMessagesMessageInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .thread_messages() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_thread_messages_message_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PutApiV1ThreadMessagesMessageInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .thread_messages() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_thread_messages_message_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PutApiV1ThreadMessagesMessageInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .thread_messages() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_thread_messages_message_replies_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ThreadMessagesMessageRepliesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .thread_messages() + .replies("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/thread_messages/{message}/replies", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_thread_messages_message_replies_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ThreadMessagesMessageRepliesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .thread_messages() + .replies("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_thread_messages_message_replies_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1ThreadMessagesMessageRepliesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .thread_messages() + .replies("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_thread_messages_message_replies_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1ThreadMessagesMessageRepliesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .thread_messages() + .replies("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_thread_messages_message_replies_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1ThreadMessagesMessageRepliesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .thread_messages() + .replies("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_thread_messages_message_reactions_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .thread_messages() + .reactions("test-value") + .remove() + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/thread_messages/{message}/reactions", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_thread_messages_message_reactions_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .thread_messages() + .reactions("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_thread_messages_message_reactions_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .thread_messages() + .reactions("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_thread_messages_message_reactions_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .thread_messages() + .reactions("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_thread_messages_message_reactions_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .thread_messages() + .reactions("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_thread_messages_message_reactions_success() { + let client = support::rest_client(None).await; + let body: PostApiV1ThreadMessagesMessageReactionsInput = + serde_json::from_str(r#"{"emoji":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .thread_messages() + .reactions("test-value") + .create(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/thread_messages/{message}/reactions", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_thread_messages_message_reactions_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1ThreadMessagesMessageReactionsInput = + serde_json::from_str(r#"{"emoji":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .thread_messages() + .reactions("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_thread_messages_message_reactions_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1ThreadMessagesMessageReactionsInput = + serde_json::from_str(r#"{"emoji":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .thread_messages() + .reactions("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_thread_messages_message_reactions_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1ThreadMessagesMessageReactionsInput = + serde_json::from_str(r#"{"emoji":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .thread_messages() + .reactions("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_thread_messages_message_reactions_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1ThreadMessagesMessageReactionsInput = + serde_json::from_str(r#"{"emoji":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .thread_messages() + .reactions("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_success() { + let client = support::rest_client(None).await; + let result = client.v1().threads().delete("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/threads/{thread}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .threads() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .threads() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .threads() + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_success() { + let client = support::rest_client(None).await; + let result = client.v1().threads().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/threads/{thread}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .threads() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .threads() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .threads() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_success() { + let client = support::rest_client(None).await; + let body: PutApiV1ThreadsThreadInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().threads().replace("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "PUT /api/v1/threads/{thread}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PutApiV1ThreadsThreadInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PutApiV1ThreadsThreadInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PutApiV1ThreadsThreadInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PutApiV1ThreadsThreadInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PutApiV1ThreadsThreadInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .replace("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_agents_success() { + let client = support::rest_client(None).await; + let result = client.v1().threads().agents("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/threads/{thread}/agents", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_agents_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .threads() + .agents("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_agents_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .threads() + .agents("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_agents_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .threads() + .agents("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_artifacts_success() { + let client = support::rest_client(None).await; + let result = client.v1().threads().artifacts("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/threads/{thread}/artifacts", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_artifacts_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .threads() + .artifacts("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_artifacts_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .threads() + .artifacts("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_artifacts_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .threads() + .artifacts("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_mark_read_success() { + let client = support::rest_client(None).await; + let body: PostApiV1ThreadsThreadMarkReadInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().threads().mark_read("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/threads/{thread}/mark_read", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_mark_read_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1ThreadsThreadMarkReadInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .mark_read("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_mark_read_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1ThreadsThreadMarkReadInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .mark_read("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_mark_read_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1ThreadsThreadMarkReadInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .mark_read("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_messages_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ThreadsThreadMessagesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .threads() + .messages("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/threads/{thread}/messages", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_messages_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1ThreadsThreadMessagesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .messages("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_messages_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ThreadsThreadMessagesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .messages("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_messages_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1ThreadsThreadMessagesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .messages("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_messages_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1ThreadsThreadMessagesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .messages("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_picture_success() { + let client = support::rest_client(None).await; + let body: PutApiV1ThreadsThreadPictureInput = serde_json::from_str( + r#"{"picture":{"data":"string","filename":"avatar.png","mime_type":"application/json"}}"#, + ) + .expect("valid generated body"); + let result = client.v1().threads().picture("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "PUT /api/v1/threads/{thread}/picture", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_picture_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PutApiV1ThreadsThreadPictureInput = serde_json::from_str( + r#"{"picture":{"data":"string","filename":"avatar.png","mime_type":"application/json"}}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .threads() + .picture("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_picture_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PutApiV1ThreadsThreadPictureInput = serde_json::from_str( + r#"{"picture":{"data":"string","filename":"avatar.png","mime_type":"application/json"}}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .threads() + .picture("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_picture_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PutApiV1ThreadsThreadPictureInput = serde_json::from_str( + r#"{"picture":{"data":"string","filename":"avatar.png","mime_type":"application/json"}}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .threads() + .picture("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_picture_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PutApiV1ThreadsThreadPictureInput = serde_json::from_str( + r#"{"picture":{"data":"string","filename":"avatar.png","mime_type":"application/json"}}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .threads() + .picture("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_read_status_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ThreadsThreadReadStatusParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .threads() + .read_status("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/threads/{thread}/read_status", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_read_status_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ThreadsThreadReadStatusParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .read_status("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_read_status_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1ThreadsThreadReadStatusParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .read_status("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_read_status_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1ThreadsThreadReadStatusParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .read_status("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_search_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ThreadsThreadSearchParams = + serde_json::from_str(r#"{"q":"string"}"#).expect("valid generated params"); + let result = client.v1().threads().search("test-value", ¶ms).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/threads/{thread}/search", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_search_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1ThreadsThreadSearchParams = + serde_json::from_str(r#"{"q":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .search("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_search_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ThreadsThreadSearchParams = + serde_json::from_str(r#"{"q":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .search("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_search_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1ThreadsThreadSearchParams = + serde_json::from_str(r#"{"q":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .search("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_search_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1ThreadsThreadSearchParams = + serde_json::from_str(r#"{"q":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .search("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_search_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1ThreadsThreadSearchParams = + serde_json::from_str(r#"{"q":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .search("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_search_error_502() { + let client = support::rest_client(Some(502)).await; + let params: GetApiV1ThreadsThreadSearchParams = + serde_json::from_str(r#"{"q":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .search("test-value", ¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 502); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_trajectories_success() { + let client = support::rest_client(None).await; + let params: GetApiV1ThreadsThreadTrajectoriesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .threads() + .trajectories("test-value", Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/threads/{thread}/trajectories", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_trajectories_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1ThreadsThreadTrajectoriesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .trajectories("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_trajectories_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1ThreadsThreadTrajectoriesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .trajectories("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_trajectories_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1ThreadsThreadTrajectoriesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .threads() + .trajectories("test-value", Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_members_success() { + let client = support::rest_client(None).await; + let result = client.v1().threads().members("test-value").remove().await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/threads/{thread}/members", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_members_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .threads() + .members("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_members_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .threads() + .members("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_members_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .threads() + .members("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_members_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .threads() + .members("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_members_success() { + let client = support::rest_client(None).await; + let result = client.v1().threads().members("test-value").list().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/threads/{thread}/members", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_members_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .threads() + .members("test-value") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_members_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .threads() + .members("test-value") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_members_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .threads() + .members("test-value") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_members_success() { + let client = support::rest_client(None).await; + let body: PostApiV1ThreadsThreadMembersInput = + serde_json::from_str(r#"{"type":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .threads() + .members("test-value") + .create(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/threads/{thread}/members", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_members_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1ThreadsThreadMembersInput = + serde_json::from_str(r#"{"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .members("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_members_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1ThreadsThreadMembersInput = + serde_json::from_str(r#"{"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .members("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_members_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1ThreadsThreadMembersInput = + serde_json::from_str(r#"{"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .members("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_members_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1ThreadsThreadMembersInput = + serde_json::from_str(r#"{"type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .members("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_settings_success() { + let client = support::rest_client(None).await; + let result = client.v1().threads().settings("test-value").list().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/threads/{thread}/settings", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_settings_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .threads() + .settings("test-value") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_settings_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .threads() + .settings("test-value") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_threads_thread_settings_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .threads() + .settings("test-value") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_settings_success() { + let client = support::rest_client(None).await; + let body: PutApiV1ThreadsThreadSettingsInput = + serde_json::from_str(r#"{"settings":{}}"#).expect("valid generated body"); + let result = client + .v1() + .threads() + .settings("test-value") + .replace(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "PUT /api/v1/threads/{thread}/settings", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_settings_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PutApiV1ThreadsThreadSettingsInput = + serde_json::from_str(r#"{"settings":{}}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .settings("test-value") + .replace(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_settings_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PutApiV1ThreadsThreadSettingsInput = + serde_json::from_str(r#"{"settings":{}}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .settings("test-value") + .replace(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_settings_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PutApiV1ThreadsThreadSettingsInput = + serde_json::from_str(r#"{"settings":{}}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .settings("test-value") + .replace(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_settings_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PutApiV1ThreadsThreadSettingsInput = + serde_json::from_str(r#"{"settings":{}}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .settings("test-value") + .replace(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_tags_success() { + let client = support::rest_client(None).await; + let result = client.v1().threads().tags("test-value").remove().await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/threads/{thread}/tags", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_tags_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .threads() + .tags("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_tags_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .threads() + .tags("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_tags_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .threads() + .tags("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_threads_thread_tags_error_422() { + let client = support::rest_client(Some(422)).await; + let error = client + .v1() + .threads() + .tags("test-value") + .remove() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_tags_success() { + let client = support::rest_client(None).await; + let body: PostApiV1ThreadsThreadTagsInput = + serde_json::from_str(r#"{"tags":["string"]}"#).expect("valid generated body"); + let result = client.v1().threads().tags("test-value").create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/threads/{thread}/tags", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_tags_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1ThreadsThreadTagsInput = + serde_json::from_str(r#"{"tags":["string"]}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .tags("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_tags_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1ThreadsThreadTagsInput = + serde_json::from_str(r#"{"tags":["string"]}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .tags("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_tags_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1ThreadsThreadTagsInput = + serde_json::from_str(r#"{"tags":["string"]}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .tags("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_threads_thread_tags_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1ThreadsThreadTagsInput = + serde_json::from_str(r#"{"tags":["string"]}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .tags("test-value") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_tags_success() { + let client = support::rest_client(None).await; + let body: PutApiV1ThreadsThreadTagsInput = + serde_json::from_str(r#"{"tags":["string"]}"#).expect("valid generated body"); + let result = client + .v1() + .threads() + .tags("test-value") + .replace(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "PUT /api/v1/threads/{thread}/tags", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_tags_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PutApiV1ThreadsThreadTagsInput = + serde_json::from_str(r#"{"tags":["string"]}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .tags("test-value") + .replace(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_tags_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PutApiV1ThreadsThreadTagsInput = + serde_json::from_str(r#"{"tags":["string"]}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .tags("test-value") + .replace(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_tags_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PutApiV1ThreadsThreadTagsInput = + serde_json::from_str(r#"{"tags":["string"]}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .tags("test-value") + .replace(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_threads_thread_tags_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PutApiV1ThreadsThreadTagsInput = + serde_json::from_str(r#"{"tags":["string"]}"#).expect("valid generated body"); + let error = client + .v1() + .threads() + .tags("test-value") + .replace(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_trajectories_trajectory_success() { + let client = support::rest_client(None).await; + let result = client.v1().trajectories().get("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/trajectories/{trajectory}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_trajectories_trajectory_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .trajectories() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_trajectories_trajectory_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .trajectories() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_trajectories_trajectory_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .trajectories() + .get("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_trajectories_trajectory_contents_success() { + let client = support::rest_client(None).await; + let result = client.v1().trajectories().contents("test-value").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/trajectories/{trajectory}/contents", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_trajectories_trajectory_contents_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .trajectories() + .contents("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_trajectories_trajectory_contents_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .trajectories() + .contents("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_trajectories_trajectory_contents_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .trajectories() + .contents("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_me_success() { + let client = support::rest_client(None).await; + let result = client.v1().users().me().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/users/me", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_me_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .users() + .me() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_success() { + let client = support::rest_client(None).await; + let result = client.v1().users().get("test-id").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/users/{user}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .users() + .get("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .users() + .get("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_artifacts_success() { + let client = support::rest_client(None).await; + let result = client.v1().users().artifacts("test-id").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/users/{user}/artifacts", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_artifacts_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .users() + .artifacts("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_artifacts_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .users() + .artifacts("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_invites_success() { + let client = support::rest_client(None).await; + let body: PostApiV1UsersUserInvitesInput = serde_json::from_str( + r#"{"invite":{"metadata":{"key":"value"},"persona_id":"string","thread_id":"string"}}"#, + ) + .expect("valid generated body"); + let result = client.v1().users().invites("test-id", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/users/{user}/invites", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_invites_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1UsersUserInvitesInput = serde_json::from_str( + r#"{"invite":{"metadata":{"key":"value"},"persona_id":"string","thread_id":"string"}}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .users() + .invites("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_invites_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1UsersUserInvitesInput = serde_json::from_str( + r#"{"invite":{"metadata":{"key":"value"},"persona_id":"string","thread_id":"string"}}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .users() + .invites("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_invites_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1UsersUserInvitesInput = serde_json::from_str( + r#"{"invite":{"metadata":{"key":"value"},"persona_id":"string","thread_id":"string"}}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .users() + .invites("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_invites_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1UsersUserInvitesInput = serde_json::from_str( + r#"{"invite":{"metadata":{"key":"value"},"persona_id":"string","thread_id":"string"}}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .users() + .invites("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_invites_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1UsersUserInvitesInput = serde_json::from_str( + r#"{"invite":{"metadata":{"key":"value"},"persona_id":"string","thread_id":"string"}}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .users() + .invites("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_orgs_success() { + let client = support::rest_client(None).await; + let result = client.v1().users().orgs("test-id").await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/users/{user}/orgs", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_orgs_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .users() + .orgs("test-id") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_users_user_profile_success() { + let client = support::rest_client(None).await; + let body: PutApiV1UsersUserProfileInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().users().profile("test-id", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "PUT /api/v1/users/{user}/profile", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_users_user_profile_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PutApiV1UsersUserProfileInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .users() + .profile("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn put_api_v1_users_user_profile_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PutApiV1UsersUserProfileInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .users() + .profile("test-id", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_success() { + let client = support::rest_client(None).await; + let params: GetApiV1UsersUserTasksParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .users() + .tasks("test-id") + .list(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/users/{user}/tasks", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1UsersUserTasksParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .tasks("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1UsersUserTasksParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .tasks("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1UsersUserTasksParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .tasks("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_tasks_success() { + let client = support::rest_client(None).await; + let body: PostApiV1UsersUserTasksInput = serde_json::from_str(r#"{"task":{"description":"An example description.","due_date":"2024-01-01T00:00:00Z","links":{"key":"value"},"metadata":{"key":"value"},"name":"Example Name","owner_agent":"string","owner_user":"string","parent":"tsk_01j3k5m7n9p2r4s6t8v0w1x2","priority":2,"status":"open","tags":["backend","q3-launch"],"thread":"thr_01j3k5m7n9p2r4s6t8v0w1x2"}}"#).expect("valid generated body"); + let result = client.v1().users().tasks("test-id").create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/users/{user}/tasks", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_tasks_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1UsersUserTasksInput = serde_json::from_str(r#"{"task":{"description":"An example description.","due_date":"2024-01-01T00:00:00Z","links":{"key":"value"},"metadata":{"key":"value"},"name":"Example Name","owner_agent":"string","owner_user":"string","parent":"tsk_01j3k5m7n9p2r4s6t8v0w1x2","priority":2,"status":"open","tags":["backend","q3-launch"],"thread":"thr_01j3k5m7n9p2r4s6t8v0w1x2"}}"#).expect("valid generated body"); + let error = client + .v1() + .users() + .tasks("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_tasks_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1UsersUserTasksInput = serde_json::from_str(r#"{"task":{"description":"An example description.","due_date":"2024-01-01T00:00:00Z","links":{"key":"value"},"metadata":{"key":"value"},"name":"Example Name","owner_agent":"string","owner_user":"string","parent":"tsk_01j3k5m7n9p2r4s6t8v0w1x2","priority":2,"status":"open","tags":["backend","q3-launch"],"thread":"thr_01j3k5m7n9p2r4s6t8v0w1x2"}}"#).expect("valid generated body"); + let error = client + .v1() + .users() + .tasks("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_tasks_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1UsersUserTasksInput = serde_json::from_str(r#"{"task":{"description":"An example description.","due_date":"2024-01-01T00:00:00Z","links":{"key":"value"},"metadata":{"key":"value"},"name":"Example Name","owner_agent":"string","owner_user":"string","parent":"tsk_01j3k5m7n9p2r4s6t8v0w1x2","priority":2,"status":"open","tags":["backend","q3-launch"],"thread":"thr_01j3k5m7n9p2r4s6t8v0w1x2"}}"#).expect("valid generated body"); + let error = client + .v1() + .users() + .tasks("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_blocker_cycles_success() { + let client = support::rest_client(None).await; + let params: GetApiV1UsersUserTasksBlockerCyclesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .users() + .tasks("test-id") + .blocker_cycles(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/users/{user}/tasks/blocker_cycles", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_blocker_cycles_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1UsersUserTasksBlockerCyclesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .tasks("test-id") + .blocker_cycles(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_blocker_cycles_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1UsersUserTasksBlockerCyclesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .tasks("test-id") + .blocker_cycles(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_blocker_cycles_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1UsersUserTasksBlockerCyclesParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .tasks("test-id") + .blocker_cycles(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_ready_success() { + let client = support::rest_client(None).await; + let params: GetApiV1UsersUserTasksReadyParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .users() + .tasks("test-id") + .ready(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/users/{user}/tasks/ready", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_ready_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1UsersUserTasksReadyParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .tasks("test-id") + .ready(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_ready_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1UsersUserTasksReadyParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .tasks("test-id") + .ready(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_ready_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1UsersUserTasksReadyParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .tasks("test-id") + .ready(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_search_success() { + let client = support::rest_client(None).await; + let params: GetApiV1UsersUserTasksSearchParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .users() + .tasks("test-id") + .search(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/users/{user}/tasks/search", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_search_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1UsersUserTasksSearchParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .tasks("test-id") + .search(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_search_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1UsersUserTasksSearchParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .tasks("test-id") + .search(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tasks_search_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1UsersUserTasksSearchParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .tasks("test-id") + .search(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_threads_success() { + let client = support::rest_client(None).await; + let params: GetApiV1UsersUserThreadsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client + .v1() + .users() + .threads("test-id") + .list(Some(¶ms)) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/users/{user}/threads", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_threads_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1UsersUserThreadsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .threads("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_threads_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1UsersUserThreadsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .users() + .threads("test-id") + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_threads_success() { + let client = support::rest_client(None).await; + let body: PostApiV1UsersUserThreadsInput = serde_json::from_str(r#"{"thread":{"create_legacy_agent":true,"description":"An example description.","is_unlisted":true,"key":"string","members":[{"id":"string","type":"user"}],"metadata":{"key":"value"},"muted":true,"org_id":"string","profile_picture":{"data":"string","filename":"string","mime_type":"application/json"},"settings":{"agent_enabled":true},"slug":"example-slug","title":"Example Title","visibility":"team"}}"#).expect("valid generated body"); + let result = client.v1().users().threads("test-id").create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/users/{user}/threads", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_threads_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1UsersUserThreadsInput = serde_json::from_str(r#"{"thread":{"create_legacy_agent":true,"description":"An example description.","is_unlisted":true,"key":"string","members":[{"id":"string","type":"user"}],"metadata":{"key":"value"},"muted":true,"org_id":"string","profile_picture":{"data":"string","filename":"string","mime_type":"application/json"},"settings":{"agent_enabled":true},"slug":"example-slug","title":"Example Title","visibility":"team"}}"#).expect("valid generated body"); + let error = client + .v1() + .users() + .threads("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_threads_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1UsersUserThreadsInput = serde_json::from_str(r#"{"thread":{"create_legacy_agent":true,"description":"An example description.","is_unlisted":true,"key":"string","members":[{"id":"string","type":"user"}],"metadata":{"key":"value"},"muted":true,"org_id":"string","profile_picture":{"data":"string","filename":"string","mime_type":"application/json"},"settings":{"agent_enabled":true},"slug":"example-slug","title":"Example Title","visibility":"team"}}"#).expect("valid generated body"); + let error = client + .v1() + .users() + .threads("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_threads_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1UsersUserThreadsInput = serde_json::from_str(r#"{"thread":{"create_legacy_agent":true,"description":"An example description.","is_unlisted":true,"key":"string","members":[{"id":"string","type":"user"}],"metadata":{"key":"value"},"muted":true,"org_id":"string","profile_picture":{"data":"string","filename":"string","mime_type":"application/json"},"settings":{"agent_enabled":true},"slug":"example-slug","title":"Example Title","visibility":"team"}}"#).expect("valid generated body"); + let error = client + .v1() + .users() + .threads("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tokens_success() { + let client = support::rest_client(None).await; + let result = client.v1().users().tokens("test-id").list().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/users/{user}/tokens", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tokens_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .users() + .tokens("test-id") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_users_user_tokens_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .users() + .tokens("test-id") + .list() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_tokens_success() { + let client = support::rest_client(None).await; + let body: PostApiV1UsersUserTokensInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.v1().users().tokens("test-id").create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/users/{user}/tokens", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_tokens_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1UsersUserTokensInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .users() + .tokens("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_tokens_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1UsersUserTokensInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .users() + .tokens("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_tokens_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1UsersUserTokensInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .users() + .tokens("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_users_user_tokens_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostApiV1UsersUserTokensInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .v1() + .users() + .tokens("test-id") + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_users_user_tokens_token_success() { + let client = support::rest_client(None).await; + let result = client + .v1() + .users() + .tokens("test-id") + .delete("test-value") + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "DELETE /api/v1/users/{user}/tokens/{token}", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_users_user_tokens_token_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .users() + .tokens("test-id") + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_users_user_tokens_token_error_403() { + let client = support::rest_client(Some(403)).await; + let error = client + .v1() + .users() + .tokens("test-id") + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn delete_api_v1_users_user_tokens_token_error_404() { + let client = support::rest_client(Some(404)).await; + let error = client + .v1() + .users() + .tokens("test-id") + .delete("test-value") + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_work_items_success() { + let client = support::rest_client(None).await; + let params: GetApiV1WorkItemsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let result = client.v1().work_items().list(Some(¶ms)).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/work_items", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_work_items_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetApiV1WorkItemsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .work_items() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_work_items_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetApiV1WorkItemsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .work_items() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_work_items_error_403() { + let client = support::rest_client(Some(403)).await; + let params: GetApiV1WorkItemsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .work_items() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_work_items_error_404() { + let client = support::rest_client(Some(404)).await; + let params: GetApiV1WorkItemsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .work_items() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_work_items_error_422() { + let client = support::rest_client(Some(422)).await; + let params: GetApiV1WorkItemsParams = + serde_json::from_str(r#"{}"#).expect("valid generated params"); + let error = client + .v1() + .work_items() + .list(Some(¶ms)) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_fail_success() { + let client = support::rest_client(None).await; + let body: PostApiV1WorkItemsWorkItemFailInput = + serde_json::from_str(r#"{"error":{},"lease_owner":"string"}"#) + .expect("valid generated body"); + let result = client.v1().work_items().fail("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/work_items/{work_item}/fail", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_fail_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1WorkItemsWorkItemFailInput = + serde_json::from_str(r#"{"error":{},"lease_owner":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .work_items() + .fail("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_fail_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1WorkItemsWorkItemFailInput = + serde_json::from_str(r#"{"error":{},"lease_owner":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .work_items() + .fail("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_fail_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1WorkItemsWorkItemFailInput = + serde_json::from_str(r#"{"error":{},"lease_owner":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .work_items() + .fail("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_fail_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1WorkItemsWorkItemFailInput = + serde_json::from_str(r#"{"error":{},"lease_owner":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .work_items() + .fail("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_fail_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1WorkItemsWorkItemFailInput = + serde_json::from_str(r#"{"error":{},"lease_owner":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .work_items() + .fail("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_heartbeat_success() { + let client = support::rest_client(None).await; + let body: PostApiV1WorkItemsWorkItemHeartbeatInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let result = client + .v1() + .work_items() + .heartbeat("test-value", &body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/work_items/{work_item}/heartbeat", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_heartbeat_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1WorkItemsWorkItemHeartbeatInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .work_items() + .heartbeat("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_heartbeat_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1WorkItemsWorkItemHeartbeatInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .work_items() + .heartbeat("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_heartbeat_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1WorkItemsWorkItemHeartbeatInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .work_items() + .heartbeat("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_heartbeat_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1WorkItemsWorkItemHeartbeatInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .work_items() + .heartbeat("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_heartbeat_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1WorkItemsWorkItemHeartbeatInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .work_items() + .heartbeat("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_start_success() { + let client = support::rest_client(None).await; + let body: PostApiV1WorkItemsWorkItemStartInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let result = client.v1().work_items().start("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/work_items/{work_item}/start", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_start_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1WorkItemsWorkItemStartInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .work_items() + .start("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_start_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1WorkItemsWorkItemStartInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .work_items() + .start("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_start_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1WorkItemsWorkItemStartInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .work_items() + .start("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_start_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1WorkItemsWorkItemStartInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .work_items() + .start("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_start_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1WorkItemsWorkItemStartInput = + serde_json::from_str(r#"{"lease_owner":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .work_items() + .start("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_submit_success() { + let client = support::rest_client(None).await; + let body: PostApiV1WorkItemsWorkItemSubmitInput = + serde_json::from_str(r#"{"lease_owner":"string","result":{}}"#) + .expect("valid generated body"); + let result = client.v1().work_items().submit("test-value", &body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/work_items/{work_item}/submit", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_submit_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1WorkItemsWorkItemSubmitInput = + serde_json::from_str(r#"{"lease_owner":"string","result":{}}"#) + .expect("valid generated body"); + let error = client + .v1() + .work_items() + .submit("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_submit_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1WorkItemsWorkItemSubmitInput = + serde_json::from_str(r#"{"lease_owner":"string","result":{}}"#) + .expect("valid generated body"); + let error = client + .v1() + .work_items() + .submit("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_submit_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1WorkItemsWorkItemSubmitInput = + serde_json::from_str(r#"{"lease_owner":"string","result":{}}"#) + .expect("valid generated body"); + let error = client + .v1() + .work_items() + .submit("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_submit_error_409() { + let client = support::rest_client(Some(409)).await; + let body: PostApiV1WorkItemsWorkItemSubmitInput = + serde_json::from_str(r#"{"lease_owner":"string","result":{}}"#) + .expect("valid generated body"); + let error = client + .v1() + .work_items() + .submit("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 409); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_work_items_work_item_submit_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1WorkItemsWorkItemSubmitInput = + serde_json::from_str(r#"{"lease_owner":"string","result":{}}"#) + .expect("valid generated body"); + let error = client + .v1() + .work_items() + .submit("test-value", &body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_ai_chat_models_success() { + let client = support::rest_client(None).await; + let result = client.v1().ai().chat().models().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/ai/chat/models", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_ai_chat_models_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .ai() + .chat() + .models() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_chat_completions_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AiChatCompletionsInput = serde_json::from_str(r#"{"messages":[{"content":"How can I help you today?","content_parts":[{}],"resume_token":"string","role":"user","tool_calls":[{"arguments":{},"id":"string","name":"Example Name","thought_signature":"string"}],"tool_results":[{"content":"string","id":"string","name":"Example Name"}]}],"opts":{"max_tokens":1,"model":"string","server_tools":[{}],"structured_output":{},"temperature":1,"tool_choice":"string","tools":[{"function":{"description":"An example description.","name":"Example Name","parameters":{}},"type":"function"}]}}"#).expect("valid generated body"); + let result = client.v1().ai().chat().completions().create(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/ai/chat/completions", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_chat_completions_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AiChatCompletionsInput = serde_json::from_str(r#"{"messages":[{"content":"How can I help you today?","content_parts":[{}],"resume_token":"string","role":"user","tool_calls":[{"arguments":{},"id":"string","name":"Example Name","thought_signature":"string"}],"tool_results":[{"content":"string","id":"string","name":"Example Name"}]}],"opts":{"max_tokens":1,"model":"string","server_tools":[{}],"structured_output":{},"temperature":1,"tool_choice":"string","tools":[{"function":{"description":"An example description.","name":"Example Name","parameters":{}},"type":"function"}]}}"#).expect("valid generated body"); + let error = client + .v1() + .ai() + .chat() + .completions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_chat_completions_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AiChatCompletionsInput = serde_json::from_str(r#"{"messages":[{"content":"How can I help you today?","content_parts":[{}],"resume_token":"string","role":"user","tool_calls":[{"arguments":{},"id":"string","name":"Example Name","thought_signature":"string"}],"tool_results":[{"content":"string","id":"string","name":"Example Name"}]}],"opts":{"max_tokens":1,"model":"string","server_tools":[{}],"structured_output":{},"temperature":1,"tool_choice":"string","tools":[{"function":{"description":"An example description.","name":"Example Name","parameters":{}},"type":"function"}]}}"#).expect("valid generated body"); + let error = client + .v1() + .ai() + .chat() + .completions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_chat_completions_error_402() { + let client = support::rest_client(Some(402)).await; + let body: PostApiV1AiChatCompletionsInput = serde_json::from_str(r#"{"messages":[{"content":"How can I help you today?","content_parts":[{}],"resume_token":"string","role":"user","tool_calls":[{"arguments":{},"id":"string","name":"Example Name","thought_signature":"string"}],"tool_results":[{"content":"string","id":"string","name":"Example Name"}]}],"opts":{"max_tokens":1,"model":"string","server_tools":[{}],"structured_output":{},"temperature":1,"tool_choice":"string","tools":[{"function":{"description":"An example description.","name":"Example Name","parameters":{}},"type":"function"}]}}"#).expect("valid generated body"); + let error = client + .v1() + .ai() + .chat() + .completions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 402); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_chat_completions_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AiChatCompletionsInput = serde_json::from_str(r#"{"messages":[{"content":"How can I help you today?","content_parts":[{}],"resume_token":"string","role":"user","tool_calls":[{"arguments":{},"id":"string","name":"Example Name","thought_signature":"string"}],"tool_results":[{"content":"string","id":"string","name":"Example Name"}]}],"opts":{"max_tokens":1,"model":"string","server_tools":[{}],"structured_output":{},"temperature":1,"tool_choice":"string","tools":[{"function":{"description":"An example description.","name":"Example Name","parameters":{}},"type":"function"}]}}"#).expect("valid generated body"); + let error = client + .v1() + .ai() + .chat() + .completions() + .create(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_embedding_similarity_comparison_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AiEmbeddingSimilarityComparisonInput = + serde_json::from_str(r#"{"text_a":"string","text_b":"string"}"#) + .expect("valid generated body"); + let result = client + .v1() + .ai() + .embedding() + .similarity_comparison(&body) + .await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/ai/embedding/similarity_comparison", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_embedding_similarity_comparison_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AiEmbeddingSimilarityComparisonInput = + serde_json::from_str(r#"{"text_a":"string","text_b":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .ai() + .embedding() + .similarity_comparison(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_embedding_similarity_comparison_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AiEmbeddingSimilarityComparisonInput = + serde_json::from_str(r#"{"text_a":"string","text_b":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .ai() + .embedding() + .similarity_comparison(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_embedding_similarity_comparison_error_402() { + let client = support::rest_client(Some(402)).await; + let body: PostApiV1AiEmbeddingSimilarityComparisonInput = + serde_json::from_str(r#"{"text_a":"string","text_b":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .ai() + .embedding() + .similarity_comparison(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 402); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_embedding_similarity_comparison_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AiEmbeddingSimilarityComparisonInput = + serde_json::from_str(r#"{"text_a":"string","text_b":"string"}"#) + .expect("valid generated body"); + let error = client + .v1() + .ai() + .embedding() + .similarity_comparison(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_image_edits_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AiImageEditsInput = serde_json::from_str( + r#"{"images":[{"image_data":"string","image_type":"image/png"}],"prompt":"string"}"#, + ) + .expect("valid generated body"); + let result = client.v1().ai().image().edits(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/ai/image/edits", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_image_edits_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AiImageEditsInput = serde_json::from_str( + r#"{"images":[{"image_data":"string","image_type":"image/png"}],"prompt":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .ai() + .image() + .edits(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_image_edits_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AiImageEditsInput = serde_json::from_str( + r#"{"images":[{"image_data":"string","image_type":"image/png"}],"prompt":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .ai() + .image() + .edits(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_image_edits_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AiImageEditsInput = serde_json::from_str( + r#"{"images":[{"image_data":"string","image_type":"image/png"}],"prompt":"string"}"#, + ) + .expect("valid generated body"); + let error = client + .v1() + .ai() + .image() + .edits(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_image_generations_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AiImageGenerationsInput = + serde_json::from_str(r#"{"prompt":"string"}"#).expect("valid generated body"); + let result = client.v1().ai().image().generations(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/ai/image/generations", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_image_generations_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AiImageGenerationsInput = + serde_json::from_str(r#"{"prompt":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .ai() + .image() + .generations(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_image_generations_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AiImageGenerationsInput = + serde_json::from_str(r#"{"prompt":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .ai() + .image() + .generations(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_ai_image_generations_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AiImageGenerationsInput = + serde_json::from_str(r#"{"prompt":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .ai() + .image() + .generations(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_ai_image_models_success() { + let client = support::rest_client(None).await; + let result = client.v1().ai().image().models().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/ai/image/models", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_ai_image_models_error_401() { + let client = support::rest_client(Some(401)).await; + let error = client + .v1() + .ai() + .image() + .models() + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_oauth_scopes_success() { + let client = support::rest_client(None).await; + let result = client.v1().oauth().scopes().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /oauth/scopes", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_token_success() { + let client = support::rest_client(None).await; + let body: PostOauthTokenInput = + serde_json::from_str(r#"{"grant_type":"string"}"#).expect("valid generated body"); + let result = client.v1().oauth().token(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /oauth/token", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_token_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostOauthTokenInput = + serde_json::from_str(r#"{"grant_type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .oauth() + .token(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_token_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostOauthTokenInput = + serde_json::from_str(r#"{"grant_type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .oauth() + .token(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_token_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostOauthTokenInput = + serde_json::from_str(r#"{"grant_type":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .oauth() + .token(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_device_approve_success() { + let client = support::rest_client(None).await; + let body: PostOauthDeviceApproveInput = + serde_json::from_str(r#"{"user_code":"string"}"#).expect("valid generated body"); + let result = client.v1().oauth().device().approve(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /oauth/device/approve", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_device_approve_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostOauthDeviceApproveInput = + serde_json::from_str(r#"{"user_code":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .oauth() + .device() + .approve(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_device_approve_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostOauthDeviceApproveInput = + serde_json::from_str(r#"{"user_code":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .oauth() + .device() + .approve(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_oauth_device_authorization_success() { + let client = support::rest_client(None).await; + let params: GetOauthDeviceAuthorizationParams = + serde_json::from_str(r#"{"code":"string"}"#).expect("valid generated params"); + let result = client.v1().oauth().device().authorization(¶ms).await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /oauth/device/authorization", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_oauth_device_authorization_error_400() { + let client = support::rest_client(Some(400)).await; + let params: GetOauthDeviceAuthorizationParams = + serde_json::from_str(r#"{"code":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .oauth() + .device() + .authorization(¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_oauth_device_authorization_error_401() { + let client = support::rest_client(Some(401)).await; + let params: GetOauthDeviceAuthorizationParams = + serde_json::from_str(r#"{"code":"string"}"#).expect("valid generated params"); + let error = client + .v1() + .oauth() + .device() + .authorization(¶ms) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_device_authorize_success() { + let client = support::rest_client(None).await; + let body: PostOauthDeviceAuthorizeInput = + serde_json::from_str(r#"{"client":"string"}"#).expect("valid generated body"); + let result = client.v1().oauth().device().authorize(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /oauth/device/authorize", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_device_authorize_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostOauthDeviceAuthorizeInput = + serde_json::from_str(r#"{"client":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .oauth() + .device() + .authorize(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_device_authorize_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostOauthDeviceAuthorizeInput = + serde_json::from_str(r#"{"client":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .oauth() + .device() + .authorize(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_device_authorize_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostOauthDeviceAuthorizeInput = + serde_json::from_str(r#"{"client":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .oauth() + .device() + .authorize(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_device_deny_success() { + let client = support::rest_client(None).await; + let body: PostOauthDeviceDenyInput = + serde_json::from_str(r#"{"user_code":"string"}"#).expect("valid generated body"); + let result = client.v1().oauth().device().deny(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /oauth/device/deny", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_device_deny_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostOauthDeviceDenyInput = + serde_json::from_str(r#"{"user_code":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .oauth() + .device() + .deny(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_oauth_device_deny_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostOauthDeviceDenyInput = + serde_json::from_str(r#"{"user_code":"string"}"#).expect("valid generated body"); + let error = client + .v1() + .oauth() + .device() + .deny(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn get_api_v1_auth_allowed_auth_methods_success() { + let client = support::rest_client(None).await; + let result = client.auth().get_api_v1_auth_allowed_auth_methods().await; + assert!( + result.is_ok(), + "{}: {:?}", + "GET /api/v1/auth/allowed_auth_methods", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_login_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AuthLoginInput = + serde_json::from_str(r#"{"email":"user@example.com","password":"string"}"#) + .expect("valid generated body"); + let result = client.auth().post_api_v1_auth_login(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/auth/login", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_login_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AuthLoginInput = + serde_json::from_str(r#"{"email":"user@example.com","password":"string"}"#) + .expect("valid generated body"); + let error = client + .auth() + .post_api_v1_auth_login(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_login_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AuthLoginInput = + serde_json::from_str(r#"{"email":"user@example.com","password":"string"}"#) + .expect("valid generated body"); + let error = client + .auth() + .post_api_v1_auth_login(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_login_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostApiV1AuthLoginInput = + serde_json::from_str(r#"{"email":"user@example.com","password":"string"}"#) + .expect("valid generated body"); + let error = client + .auth() + .post_api_v1_auth_login(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_login_link_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AuthLoginLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.auth().request_login_magic_link(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/auth/login/link", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_login_link_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AuthLoginLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .auth() + .request_login_magic_link(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_login_link_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostApiV1AuthLoginLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .auth() + .request_login_magic_link(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_refresh_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AuthRefreshInput = + serde_json::from_str(r#"{"refresh_token":"string"}"#).expect("valid generated body"); + let result = client.auth().post_api_v1_auth_refresh(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/auth/refresh", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_refresh_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AuthRefreshInput = + serde_json::from_str(r#"{"refresh_token":"string"}"#).expect("valid generated body"); + let error = client + .auth() + .post_api_v1_auth_refresh(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_refresh_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostApiV1AuthRefreshInput = + serde_json::from_str(r#"{"refresh_token":"string"}"#).expect("valid generated body"); + let error = client + .auth() + .post_api_v1_auth_refresh(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_register_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AuthRegisterInput = + serde_json::from_str(r#"{"email":"user@example.com"}"#).expect("valid generated body"); + let result = client.auth().post_api_v1_auth_register(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/auth/register", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_register_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AuthRegisterInput = + serde_json::from_str(r#"{"email":"user@example.com"}"#).expect("valid generated body"); + let error = client + .auth() + .post_api_v1_auth_register(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_register_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AuthRegisterInput = + serde_json::from_str(r#"{"email":"user@example.com"}"#).expect("valid generated body"); + let error = client + .auth() + .post_api_v1_auth_register(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_register_error_404() { + let client = support::rest_client(Some(404)).await; + let body: PostApiV1AuthRegisterInput = + serde_json::from_str(r#"{"email":"user@example.com"}"#).expect("valid generated body"); + let error = client + .auth() + .post_api_v1_auth_register(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 404); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_register_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AuthRegisterInput = + serde_json::from_str(r#"{"email":"user@example.com"}"#).expect("valid generated body"); + let error = client + .auth() + .post_api_v1_auth_register(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_register_link_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AuthRegisterLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.auth().request_register_magic_link(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/auth/register/link", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_register_link_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AuthRegisterLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .auth() + .request_register_magic_link(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_register_link_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AuthRegisterLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .auth() + .request_register_magic_link(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_register_link_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostApiV1AuthRegisterLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .auth() + .request_register_magic_link(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_request_link_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AuthRequestLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.auth().request_magic_link(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/auth/request/link", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_request_link_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AuthRequestLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .auth() + .request_magic_link(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_request_link_error_422() { + let client = support::rest_client(Some(422)).await; + let body: PostApiV1AuthRequestLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .auth() + .request_magic_link(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 422); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_request_link_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostApiV1AuthRequestLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .auth() + .request_magic_link(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_token_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AuthTokenInput = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated body"); + let result = client.auth().exchange_login_token(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/auth/token", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_token_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AuthTokenInput = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated body"); + let error = client + .auth() + .exchange_login_token(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_token_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AuthTokenInput = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated body"); + let error = client + .auth() + .exchange_login_token(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_token_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostApiV1AuthTokenInput = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated body"); + let error = client + .auth() + .exchange_login_token(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_token_error_500() { + let client = support::rest_client(Some(500)).await; + let body: PostApiV1AuthTokenInput = + serde_json::from_str(r#"{"token":"string"}"#).expect("valid generated body"); + let error = client + .auth() + .exchange_login_token(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 500); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_verify_link_success() { + let client = support::rest_client(None).await; + let body: PostApiV1AuthVerifyLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let result = client.auth().verify_magic_link(&body).await; + assert!( + result.is_ok(), + "{}: {:?}", + "POST /api/v1/auth/verify/link", + result.err() + ); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_verify_link_error_400() { + let client = support::rest_client(Some(400)).await; + let body: PostApiV1AuthVerifyLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .auth() + .verify_magic_link(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 400); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_verify_link_error_401() { + let client = support::rest_client(Some(401)).await; + let body: PostApiV1AuthVerifyLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .auth() + .verify_magic_link(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 401); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_verify_link_error_403() { + let client = support::rest_client(Some(403)).await; + let body: PostApiV1AuthVerifyLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .auth() + .verify_magic_link(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 403); +} + +#[tokio::test] +#[ignore = "requires Prism contract server"] +async fn post_api_v1_auth_verify_link_error_429() { + let client = support::rest_client(Some(429)).await; + let body: PostApiV1AuthVerifyLinkInput = + serde_json::from_str(r#"{}"#).expect("valid generated body"); + let error = client + .auth() + .verify_magic_link(&body) + .await + .expect_err("expected API error"); + support::assert_api_error(error, 429); +} diff --git a/tests/generated_stream_contract.rs b/tests/generated_stream_contract.rs new file mode 100644 index 0000000..ddca341 --- /dev/null +++ b/tests/generated_stream_contract.rs @@ -0,0 +1,141 @@ +// Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License. +// This file is auto-generated by @archastro/sdk-generator. Do not edit. +// Content hash: e2aa44ffa5c3 + +//! Generated SSE contract tests. +mod support; +use archastro::generated::*; +use futures_util::StreamExt; + +#[test] +fn generated_support_is_linked() { + support::mark_all_used(); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn get_api_v1_agent_routine_runs_agent_routine_run_stream_events() { + let harness = support::harness().await; + harness + .register_stream( + "GET /api/v1/agent_routine_runs/{agent_routine_run}/stream", + &["run_update"], + ) + .await; + let client = harness.client(); + let mut stream = client + .v1() + .agent_routine_runs() + .stream("test-value") + .await + .expect("open stream"); + let mut count = 0usize; + while let Some(event) = stream.next().await { + event.expect("decode event"); + count += 1; + if count == 1 { + break; + } + } + assert_eq!(count, 1); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn get_api_v1_agent_sessions_agent_session_stream_events() { + let harness = support::harness().await; + harness + .register_stream( + "GET /api/v1/agent_sessions/{agent_session}/stream", + &["session_update"], + ) + .await; + let client = harness.client(); + let mut stream = client + .v1() + .agent_sessions() + .stream("test-value") + .await + .expect("open stream"); + let mut count = 0usize; + while let Some(event) = stream.next().await { + event.expect("decode event"); + count += 1; + if count == 1 { + break; + } + } + assert_eq!(count, 1); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn get_api_v1_automation_runs_automation_run_stream_events() { + let harness = support::harness().await; + harness + .register_stream( + "GET /api/v1/automation_runs/{automation_run}/stream", + &["run_update"], + ) + .await; + let client = harness.client(); + let mut stream = client + .v1() + .automation_runs() + .stream("test-value") + .await + .expect("open stream"); + let mut count = 0usize; + while let Some(event) = stream.next().await { + event.expect("decode event"); + count += 1; + if count == 1 { + break; + } + } + assert_eq!(count, 1); +} + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn post_api_v1_ai_chat_completions_stream_events() { + let harness = support::harness().await; + harness + .register_stream( + "POST /api/v1/ai/chat/completions/stream", + &[ + "done", + "error", + "message_complete", + "message_delta", + "thinking_delta", + "tool_call_delta", + "tool_result", + ], + ) + .await; + let client = harness.client(); + let body: PostApiV1AiChatCompletionsStreamInput = serde_json::from_str(r#"{"messages":[{"content":"How can I help you today?","content_parts":[{}],"resume_token":"string","role":"user","tool_calls":[{"arguments":{},"id":"string","name":"Example Name","thought_signature":"string"}],"tool_results":[{"content":"string","id":"string","name":"Example Name"}]}],"opts":{"max_tokens":1,"model":"string","server_tools":[{}],"temperature":1,"tool_choice":"string","tools":[{"function":{"description":"An example description.","name":"Example Name","parameters":{}},"type":"function"}]}}"#).expect("valid generated body"); + let mut stream = client + .v1() + .ai() + .chat() + .completions() + .stream() + .create(&body) + .await + .expect("open stream"); + let mut count = 0usize; + while let Some(event) = stream.next().await { + event.expect("decode event"); + count += 1; + if count == 7 { + break; + } + } + assert_eq!(count, 7); +} diff --git a/tests/runtime.rs b/tests/runtime.rs new file mode 100644 index 0000000..9785f92 --- /dev/null +++ b/tests/runtime.rs @@ -0,0 +1,369 @@ +//! Runtime unit and integration tests independent of generated endpoint shape. + +use archastro::sse::SseDecode; +use archastro::{AppSession, Client, Error, SessionStore}; +use futures_util::StreamExt; +use httpmock::prelude::*; +use reqwest::Method; +use serde::{Deserialize, Serialize}; +use serde_json::{Value, json}; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; + +#[derive(Debug, Serialize)] +struct Query<'a> { + search: &'a str, + page: i64, +} + +#[derive(Default)] +struct MemorySessionStore(std::sync::Mutex>); + +#[async_trait::async_trait] +impl SessionStore for MemorySessionStore { + async fn load( + &self, + ) -> std::result::Result, Box> { + Ok(self.0.lock().unwrap().clone()) + } + + async fn save( + &self, + session: &AppSession, + ) -> std::result::Result<(), Box> { + *self.0.lock().unwrap() = Some(session.clone()); + Ok(()) + } + + async fn clear(&self) -> std::result::Result<(), Box> { + *self.0.lock().unwrap() = None; + Ok(()) + } +} + +#[tokio::test] +async fn http_serializes_auth_query_and_body() { + let server = MockServer::start_async().await; + let request = server + .mock_async(|when, then| { + when.method(POST) + .path("/api/v1/widgets/a%2Fb") + .query_param("search", "two words") + .query_param("page", "2") + .header("x-archastro-api-key", "sk_test") + .header("authorization", "Bearer token") + .json_body(json!({ "enabled": true })); + then.status(200).json_body(json!({ "id": "wid_1" })); + }) + .await; + let client = Client::builder() + .base_url(server.base_url()) + .secret_key("sk_test") + .access_token("token") + .build() + .unwrap(); + let result: Value = client + .request( + Method::POST, + &format!("/api/v1/widgets/{}", archastro::encode_path("a/b")), + ) + .query(&Query { + search: "two words", + page: 2, + }) + .unwrap() + .json(&json!({ "enabled": true })) + .unwrap() + .send() + .await + .unwrap(); + assert_eq!(result["id"], "wid_1"); + request.assert_calls_async(1).await; +} + +#[tokio::test] +async fn api_errors_preserve_status_code_message_and_body() { + let server = MockServer::start_async().await; + server.mock_async(|when, then| { + when.method(GET).path("/failure"); + then.status(422).json_body(json!({ "error": { "code": "invalid_widget", "message": "bad widget" }, "trace": "abc" })); + }).await; + let client = Client::builder() + .base_url(server.base_url()) + .build() + .unwrap(); + let error = client + .request(Method::GET, "/failure") + .send::() + .await + .unwrap_err(); + match error { + Error::Api(error) => { + assert_eq!(error.status, 422); + assert_eq!(error.code.as_deref(), Some("invalid_widget")); + assert_eq!(error.message, "bad widget"); + assert_eq!(error.body["trace"], "abc"); + } + other => panic!("unexpected error: {other:?}"), + } +} + +#[tokio::test] +async fn concurrent_unauthorized_requests_share_one_single_use_refresh() { + let server = MockServer::start_async().await; + let unauthorized = server + .mock_async(|when, then| { + when.method(GET) + .path("/protected") + .header("authorization", "Bearer old"); + then.status(401).json_body(json!({ "code": "expired" })); + }) + .await; + let refresh = server + .mock_async(|when, then| { + when.method(POST) + .path("/auth/refresh") + .json_body(json!({ "refresh_token": "refresh-old" })); + then.status(200) + .json_body(json!({ "access_token": "new", "refresh_token": "refresh-new" })); + }) + .await; + let success = server + .mock_async(|when, then| { + when.method(GET) + .path("/protected") + .header("authorization", "Bearer new"); + then.status(200).json_body(json!({ "ok": true })); + }) + .await; + let client = Client::builder() + .base_url(server.base_url()) + .access_token("old") + .build() + .unwrap(); + client + .install_session("old".into(), Some("refresh-old".into()), "/auth/refresh") + .await; + + let calls = (0..12).map(|_| { + let client = client.clone(); + tokio::spawn(async move { + client + .request(Method::GET, "/protected") + .send::() + .await + .unwrap() + }) + }); + for call in calls { + assert_eq!(call.await.unwrap(), json!({ "ok": true })); + } + + assert!(unauthorized.calls_async().await >= 1); + refresh.assert_calls_async(1).await; + success.assert_calls_async(12).await; + assert_eq!(client.access_token().await.as_deref(), Some("new")); +} + +#[derive(Debug, PartialEq, Deserialize)] +struct Updated { + id: String, +} + +impl SseDecode for Updated { + fn decode(event: &str, data: &str) -> archastro::Result { + if event != "updated" { + return Err(Error::UnknownSseEvent(event.into())); + } + Ok(serde_json::from_str(data)?) + } +} + +#[tokio::test] +async fn sse_parses_fragmented_contract_events() { + let server = MockServer::start_async().await; + server + .mock_async(|when, then| { + when.method(GET).path("/events"); + then.status(200) + .header("content-type", "text/event-stream") + .body("id: 42\nevent: updated\ndata: {\"id\":\"one\"}\n\n"); + }) + .await; + let client = Client::builder() + .base_url(server.base_url()) + .build() + .unwrap(); + let mut stream = client + .request(Method::GET, "/events") + .stream::() + .await + .unwrap(); + let event = stream.next().await.unwrap().unwrap(); + assert_eq!(event.id, "42"); + assert_eq!(event.event, "updated"); + assert_eq!(event.data, Updated { id: "one".into() }); + stream.close(); +} + +#[tokio::test] +async fn sse_reconnects_after_a_flushed_transport_disconnect() { + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let address = listener.local_addr().unwrap(); + tokio::spawn(async move { + for id in ["one", "two"] { + let (mut socket, _) = listener.accept().await.unwrap(); + let mut request = vec![0_u8; 2048]; + let _ = socket.read(&mut request).await.unwrap(); + let body = format!("event: updated\ndata: {{\"id\":\"{id}\"}}\n\n"); + let response = format!( + "HTTP/1.1 200 OK\r\ncontent-type: text/event-stream\r\nconnection: close\r\n\r\n{body}" + ); + socket.write_all(response.as_bytes()).await.unwrap(); + socket.flush().await.unwrap(); + tokio::time::sleep(std::time::Duration::from_millis(25)).await; + } + }); + let client = Client::builder() + .base_url(format!("http://{address}")) + .build() + .unwrap(); + let mut stream = client + .request(Method::GET, "/events") + .stream::() + .await + .unwrap(); + assert_eq!(stream.next().await.unwrap().unwrap().data.id, "one"); + + let mut saw_disconnect = false; + tokio::time::timeout(std::time::Duration::from_secs(3), async { + loop { + match stream.next().await { + Some(Ok(event)) if saw_disconnect => { + assert_eq!(event.data.id, "two"); + break; + } + Some(Err(Error::Sse(_))) => saw_disconnect = true, + Some(_) => {} + None => panic!("stream closed instead of reconnecting"), + } + } + }) + .await + .expect("stream reconnect deadline"); +} + +#[tokio::test] +async fn sse_open_uses_the_same_single_use_refresh_contract_as_rest() { + let server = MockServer::start_async().await; + let unauthorized = server + .mock_async(|when, then| { + when.method(GET) + .path("/events") + .header("authorization", "Bearer old"); + then.status(401) + .json_body(json!({ "code": "expired", "message": "expired" })); + }) + .await; + let refresh = server + .mock_async(|when, then| { + when.method(POST) + .path("/auth/refresh") + .json_body(json!({ "refresh_token": "refresh-old" })); + then.status(200) + .json_body(json!({ "access_token": "new", "refresh_token": "refresh-new" })); + }) + .await; + let stream_response = server + .mock_async(|when, then| { + when.method(GET) + .path("/events") + .header("authorization", "Bearer new"); + then.status(200) + .header("content-type", "text/event-stream") + .body("event: updated\ndata: {\"id\":\"refreshed\"}\n\n"); + }) + .await; + let client = Client::builder() + .base_url(server.base_url()) + .access_token("old") + .build() + .unwrap(); + client + .install_session("old".into(), Some("refresh-old".into()), "/auth/refresh") + .await; + + let mut stream = client + .request(Method::GET, "/events") + .stream::() + .await + .unwrap(); + assert_eq!(stream.next().await.unwrap().unwrap().data.id, "refreshed"); + unauthorized.assert_calls_async(1).await; + refresh.assert_calls_async(1).await; + stream_response.assert_calls_async(1).await; +} + +#[tokio::test] +async fn app_sessions_restore_persist_rotation_and_sign_out() { + let server = MockServer::start_async().await; + server + .mock_async(|when, then| { + when.method(GET) + .path("/protected") + .header("authorization", "Bearer old"); + then.status(401).json_body(json!({ "code": "expired" })); + }) + .await; + let refresh = server + .mock_async(|when, then| { + when.method(POST) + .path("/api/v1/auth/refresh") + .json_body(json!({ "refresh_token": "refresh-old" })); + then.status(200) + .json_body(json!({ "access_token": "new", "refresh_token": "refresh-new" })); + }) + .await; + server + .mock_async(|when, then| { + when.method(GET) + .path("/protected") + .header("authorization", "Bearer new"); + then.status(200).json_body(json!({ "ok": true })); + }) + .await; + let store = std::sync::Arc::new(MemorySessionStore::default()); + *store.0.lock().unwrap() = Some(AppSession { + access_token: "old".into(), + refresh_token: Some("refresh-old".into()), + access_token_expires_at: Some(123), + user: Some(json!({ "id": "usr_1" })), + }); + let client = Client::builder() + .base_url(server.base_url()) + .session_store(store.clone()) + .build() + .unwrap(); + client.restore_session().await.unwrap().unwrap(); + let response: Value = client + .request(Method::GET, "/protected") + .send() + .await + .unwrap(); + assert_eq!(response, json!({ "ok": true })); + refresh.assert_calls_async(1).await; + let persisted = store.0.lock().unwrap().clone().unwrap(); + assert_eq!(persisted.access_token, "new"); + assert_eq!(persisted.refresh_token.as_deref(), Some("refresh-new")); + assert_eq!(persisted.user, Some(json!({ "id": "usr_1" }))); + + client.sign_out().await.unwrap(); + assert!(store.0.lock().unwrap().is_none()); + assert!(client.access_token().await.is_none()); +} + +#[test] +#[cfg(feature = "blocking")] +fn blocking_bridge_executes_outside_a_runtime() { + let result = archastro::blocking::block_on(async { Ok::<_, Error>(42) }).unwrap(); + assert_eq!(result, 42); +} diff --git a/tests/sse_runtime_contract.rs b/tests/sse_runtime_contract.rs new file mode 100644 index 0000000..46e1536 --- /dev/null +++ b/tests/sse_runtime_contract.rs @@ -0,0 +1,44 @@ +//! Fault-injection contracts for the hand-maintained SSE runtime. + +mod support; + +use archastro::Error; +use serde_json::json; + +const ROUTE: &str = "GET /api/v1/agent_sessions/{agent_session}/stream"; + +#[tokio::test] +#[serial_test::serial] +#[ignore = "requires channel harness"] +async fn pre_stream_http_failure_is_a_structured_api_error() { + support::mark_all_used(); + let harness = support::harness().await; + harness + .register_stream_actions( + ROUTE, + &[json!({ + "type": "status", + "code": 402, + "body": { "error": { "code": "payment_required", "message": "upgrade" } } + })], + ) + .await; + let error = match harness + .client() + .v1() + .agent_sessions() + .stream("test-value") + .await + { + Ok(_) => panic!("stream open must fail"), + Err(error) => error, + }; + match error { + Error::Api(error) => { + assert_eq!(error.status, 402); + assert_eq!(error.code.as_deref(), Some("payment_required")); + assert_eq!(error.message, "upgrade"); + } + other => panic!("expected API error, got {other:?}"), + } +} diff --git a/tests/support/mod.rs b/tests/support/mod.rs new file mode 100644 index 0000000..c572a01 --- /dev/null +++ b/tests/support/mod.rs @@ -0,0 +1,204 @@ +use std::io::BufRead; +use std::process::{Child, Command, Stdio}; +use std::sync::{Mutex, OnceLock}; +use std::time::{Duration, Instant}; + +use archastro::{Client, Error}; +use serde::Deserialize; +use serde_json::json; + +static PRISM: OnceLock> = OnceLock::new(); +static HARNESS: OnceLock<(HarnessEndpoints, Mutex)> = OnceLock::new(); + +pub fn mark_all_used() { + let _ = rest_client; + let _ = assert_api_error; + let _ = ensure_prism; + let _ = prism_port; + let _ = prism_url; + let _ = wait_for_port; + let _ = harness; + let _ = Harness::client; + let _ = Harness::socket; + let _ = Harness::register_stream; + let _ = Harness::register_stream_actions; + let _ = Harness::register_channel; + let _ = Harness::register_scenario; + let _ = Harness::ws_url; +} + +pub async fn rest_client(prefer: Option) -> Client { + ensure_prism(); + let mut builder = Client::builder() + .base_url(prism_url()) + .publishable_key("pk_test-key") + .access_token("test-token"); + if let Some(status) = prefer { + builder = builder.header("Prefer", format!("code={status}")); + } + builder.build().expect("contract client") +} + +pub fn assert_api_error(error: Error, status: u16) { + match error { + Error::Api(error) => assert_eq!(error.status, status), + other => panic!("expected API error {status}, got {other:?}"), + } +} + +fn ensure_prism() { + PRISM.get_or_init(|| { + let root = env!("CARGO_MANIFEST_DIR"); + let bin = std::env::var("PRISM_BIN") + .unwrap_or_else(|_| format!("{root}/node_modules/.bin/prism")); + let spec = std::env::var("OPENAPI_SPEC_PATH") + .unwrap_or_else(|_| format!("{root}/specs/platform-openapi.json")); + let child = Command::new(bin) + .args(["mock", &spec, "--port", prism_port(), "--host", "127.0.0.1"]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .expect("start Prism"); + wait_for_port(prism_port()); + Mutex::new(child) + }); +} + +fn prism_port() -> &'static str { + option_env!("PRISM_PORT").unwrap_or("4040") +} +fn prism_url() -> String { + format!("http://127.0.0.1:{}", prism_port()) +} + +fn wait_for_port(port: &str) { + let deadline = Instant::now() + Duration::from_secs(60); + while Instant::now() < deadline { + if std::net::TcpStream::connect(format!("127.0.0.1:{port}")).is_ok() { + return; + } + std::thread::sleep(Duration::from_millis(100)); + } + panic!("service did not listen on port {port}"); +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +struct HarnessEndpoints { + ws_url: String, + control_url: String, +} + +pub struct Harness { + endpoints: HarnessEndpoints, + http: reqwest::Client, +} + +pub async fn harness() -> Harness { + let (endpoints, _) = HARNESS.get_or_init(|| { + let root = env!("CARGO_MANIFEST_DIR"); + let bin = std::env::var("ARCHASTRO_HARNESS_BIN").unwrap_or_else(|_| { + format!("{root}/node_modules/@archastro/channel-harness/dist/bin.js") + }); + let spec = std::env::var("OPENAPI_SPEC_PATH") + .unwrap_or_else(|_| format!("{root}/specs/platform-openapi.json")); + let mut child = Command::new("node") + .args([&bin, &spec]) + .stdout(Stdio::piped()) + .stderr(Stdio::null()) + .spawn() + .expect("start channel harness"); + let line = std::io::BufReader::new(child.stdout.take().expect("harness stdout")) + .lines() + .next() + .expect("harness URL line") + .expect("read harness URL line"); + let endpoints = serde_json::from_str(&line).expect("parse harness URLs"); + (endpoints, Mutex::new(child)) + }); + let harness = Harness { + endpoints: endpoints.clone(), + http: reqwest::Client::new(), + }; + harness.post("/reset", &json!({})).await; + harness +} + +impl Harness { + pub fn ws_url(&self) -> &str { + &self.endpoints.ws_url + } + + pub fn client(&self) -> Client { + Client::builder() + .base_url(&self.endpoints.control_url) + .publishable_key("pk_test-key") + .access_token("test-token") + .build() + .expect("harness SDK client") + } + + pub async fn socket(&self) -> archastro::Socket { + archastro::SocketBuilder::new(&self.endpoints.ws_url) + .connect() + .await + .expect("harness socket") + } + + pub async fn register_stream(&self, route: &str, events: &[&str]) { + let actions: Vec<_> = events + .iter() + .map(|event| json!({ "type": "autoEmit", "event": event })) + .collect(); + self.post( + "/stream-scenarios", + &json!({ "route": route, "actions": actions }), + ) + .await; + } + + pub async fn register_stream_actions(&self, route: &str, actions: &[serde_json::Value]) { + self.post( + "/stream-scenarios", + &json!({ "route": route, "actions": actions }), + ) + .await; + } + + pub async fn register_channel(&self, topic: &str, messages: &[&str], pushes: &[&str]) { + let on_message = messages + .iter() + .map(|event| ((*event).to_owned(), json!([{ "type": "autoReply" }]))) + .collect::>(); + let mut on_join = vec![json!({ "type": "autoReply" })]; + on_join.extend( + pushes + .iter() + .map(|event| json!({ "type": "autoPush", "event": event })), + ); + self.post( + "/scenarios", + &json!({ "topic": topic, "onJoin": on_join, "onMessage": on_message }), + ) + .await; + } + + pub async fn register_scenario(&self, scenario: &serde_json::Value) { + self.post("/scenarios", scenario).await; + } + + async fn post(&self, path: &str, body: &serde_json::Value) { + let response = self + .http + .post(format!("{}{}", self.endpoints.control_url, path)) + .json(body) + .send() + .await + .expect("harness request"); + assert!( + response.status().is_success(), + "harness {path} returned {}", + response.status() + ); + } +} From 5b3c2aef39507d76e5cf2ee088a2effbf3f6515b Mon Sep 17 00:00:00 2001 From: calvin-archastro Date: Fri, 14 Aug 2026 15:25:45 -0700 Subject: [PATCH 2/3] fix(ci): keep channel harness stdout alive --- tests/support/mod.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/support/mod.rs b/tests/support/mod.rs index c572a01..5bdcecd 100644 --- a/tests/support/mod.rs +++ b/tests/support/mod.rs @@ -1,5 +1,5 @@ use std::io::BufRead; -use std::process::{Child, Command, Stdio}; +use std::process::{Child, ChildStdout, Command, Stdio}; use std::sync::{Mutex, OnceLock}; use std::time::{Duration, Instant}; @@ -8,7 +8,11 @@ use serde::Deserialize; use serde_json::json; static PRISM: OnceLock> = OnceLock::new(); -static HARNESS: OnceLock<(HarnessEndpoints, Mutex)> = OnceLock::new(); +static HARNESS: OnceLock<( + HarnessEndpoints, + Mutex, + Mutex>, +)> = OnceLock::new(); pub fn mark_all_used() { let _ = rest_client; @@ -95,7 +99,7 @@ pub struct Harness { } pub async fn harness() -> Harness { - let (endpoints, _) = HARNESS.get_or_init(|| { + let (endpoints, _, _) = HARNESS.get_or_init(|| { let root = env!("CARGO_MANIFEST_DIR"); let bin = std::env::var("ARCHASTRO_HARNESS_BIN").unwrap_or_else(|_| { format!("{root}/node_modules/@archastro/channel-harness/dist/bin.js") @@ -105,16 +109,14 @@ pub async fn harness() -> Harness { let mut child = Command::new("node") .args([&bin, &spec]) .stdout(Stdio::piped()) - .stderr(Stdio::null()) + .stderr(Stdio::inherit()) .spawn() .expect("start channel harness"); - let line = std::io::BufReader::new(child.stdout.take().expect("harness stdout")) - .lines() - .next() - .expect("harness URL line") - .expect("read harness URL line"); + let mut stdout = std::io::BufReader::new(child.stdout.take().expect("harness stdout")); + let mut line = String::new(); + stdout.read_line(&mut line).expect("read harness URL line"); let endpoints = serde_json::from_str(&line).expect("parse harness URLs"); - (endpoints, Mutex::new(child)) + (endpoints, Mutex::new(child), Mutex::new(stdout)) }); let harness = Harness { endpoints: endpoints.clone(), From 504d601876a8fa2924a127990082d0abe6c93e20 Mon Sep 17 00:00:00 2001 From: calvin-archastro Date: Fri, 14 Aug 2026 15:30:24 -0700 Subject: [PATCH 3/3] fix(ci): keep channel harness stdin open --- tests/support/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/support/mod.rs b/tests/support/mod.rs index 5bdcecd..9ab8a57 100644 --- a/tests/support/mod.rs +++ b/tests/support/mod.rs @@ -108,6 +108,7 @@ pub async fn harness() -> Harness { .unwrap_or_else(|_| format!("{root}/specs/platform-openapi.json")); let mut child = Command::new("node") .args([&bin, &spec]) + .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::inherit()) .spawn()