Skip to content

Commit 32195ec

Browse files
jmoseleyCopilot
andcommitted
Expose typed message sources in Rust send APIs
Add opt-in user/system source builders for MessageOptions and SendRequest while preserving default payloads and existing send semantics. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 1644e74 commit 32195ec

5 files changed

Lines changed: 407 additions & 37 deletions

File tree

‎rust/README.md‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,40 @@ let client = Client::start(opts).await?;
818818

819819
The SDK injects the appropriate environment variables (`COPILOT_OTEL_EXPORTER_TYPE`, `OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_EXPORTER_OTLP_PROTOCOL`, ...) into the spawned CLI process. The SDK takes no OpenTelemetry dependency; the CLI itself owns the exporter pipeline. Caller-supplied `ClientOptions::env` entries override telemetry-injected values.
820820

821+
### Message Source
822+
823+
Use `MessageSource::System` for automated messages sent by your application. Ordinary human sends leave `source` unset, so the field is omitted from the request. Use `MessageSource::User` when you need to set it explicitly.
824+
825+
```rust,no_run
826+
use github_copilot_sdk::{MessageOptions, MessageSource, session::Session};
827+
828+
# async fn example(session: &Session) -> Result<(), github_copilot_sdk::Error> {
829+
session
830+
.send(MessageOptions::new("Context updated").with_source(MessageSource::System))
831+
.await?;
832+
# Ok(())
833+
# }
834+
```
835+
836+
The raw RPC path supports the same builder, including requests with JSON attachments:
837+
838+
```rust,no_run
839+
use github_copilot_sdk::{MessageSource, rpc::SendRequest, session::Session};
840+
841+
# async fn example(session: &Session) -> Result<(), github_copilot_sdk::Error> {
842+
let mut request = SendRequest::default().with_source(MessageSource::System);
843+
request.prompt = "Context updated".into();
844+
request.attachments = Some(vec![serde_json::json!({
845+
"type": "github_url",
846+
"url": "https://github.com/github/copilot-sdk"
847+
})]);
848+
session.rpc().send(request).await?;
849+
# Ok(())
850+
# }
851+
```
852+
853+
Both paths use ordinary `session.send`. Source does not select a delivery mode or set billing flags; the runtime applies its existing source behavior. `send_and_wait` still completes on `session.idle` and may return `Ok(None)` when no assistant message was emitted. Genuine errors still propagate.
854+
821855
### Progress Reporting (`send_and_wait`)
822856

823857
For fire-and-forget messaging where you need to block until the agent finishes:

‎rust/src/rpc.rs‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,19 @@
1010
1111
pub use crate::generated::api_types::*;
1212
pub use crate::generated::rpc::*;
13+
14+
impl SendRequest {
15+
/// Set the message provenance without changing other request options.
16+
///
17+
/// When this is not called, the source field is omitted by default.
18+
pub fn with_source(mut self, source: crate::MessageSource) -> Self {
19+
self.source = Some(
20+
match source {
21+
crate::MessageSource::User => "user",
22+
crate::MessageSource::System => "system",
23+
}
24+
.to_string(),
25+
);
26+
self
27+
}
28+
}

‎rust/src/session.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,9 @@ impl Session {
522522
"sessionId": self.id,
523523
"prompt": opts.prompt,
524524
});
525+
if let Some(source) = opts.source {
526+
params["source"] = serde_json::to_value(source)?;
527+
}
525528
if let Some(m) = opts.mode {
526529
params["mode"] = serde_json::to_value(m)?;
527530
}

‎rust/src/types.rs‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5315,6 +5315,20 @@ pub fn ensure_attachment_display_names(attachments: &mut [Attachment]) {
53155315
}
53165316
}
53175317

5318+
/// Provenance of a message sent through `session.send`.
5319+
///
5320+
/// Source is independent of delivery mode. Leaving [`MessageOptions::source`]
5321+
/// unset omits the field and preserves the runtime's default for user messages.
5322+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
5323+
#[serde(rename_all = "lowercase")]
5324+
#[non_exhaustive]
5325+
pub enum MessageSource {
5326+
/// A message from a human user.
5327+
User,
5328+
/// An automated message from the integrating application.
5329+
System,
5330+
}
5331+
53185332
/// Message delivery mode for [`MessageOptions::mode`].
53195333
///
53205334
/// Controls how a prompt is delivered relative to in-flight session work.
@@ -5380,6 +5394,9 @@ pub enum AgentMode {
53805394
pub struct MessageOptions {
53815395
/// The user prompt to send.
53825396
pub prompt: String,
5397+
/// Optional message provenance. When `None`, the field is omitted,
5398+
/// preserving the runtime's default for user messages.
5399+
pub source: Option<MessageSource>,
53835400
/// Optional message delivery mode for this turn.
53845401
///
53855402
/// Controls whether the prompt is queued behind in-flight work
@@ -5419,6 +5436,7 @@ impl MessageOptions {
54195436
pub fn new(prompt: impl Into<String>) -> Self {
54205437
Self {
54215438
prompt: prompt.into(),
5439+
source: None,
54225440
mode: None,
54235441
agent_mode: None,
54245442
attachments: None,
@@ -5430,6 +5448,12 @@ impl MessageOptions {
54305448
}
54315449
}
54325450

5451+
/// Set the message provenance without changing its delivery mode.
5452+
pub fn with_source(mut self, source: MessageSource) -> Self {
5453+
self.source = Some(source);
5454+
self
5455+
}
5456+
54335457
/// Set the message delivery mode for this turn.
54345458
///
54355459
/// Pass [`DeliveryMode::Immediate`] to interrupt the session and run

0 commit comments

Comments
 (0)