Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sdk/dotnet/web-api/Corti.Sdk.Examples.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<ItemGroup>
<!-- Corti.Sdk: use local project if local.Corti.props sets CortiProjectPath, else NuGet (CI and default). -->
<ProjectReference Include="$(CortiProjectPath)" Condition="'$(CortiProjectPath)' != ''" />
<PackageReference Include="Corti.Sdk" Version="*" Condition="'$(CortiProjectPath)' == ''" />
<PackageReference Include="Corti.Sdk" Version="0.11.0" Condition="'$(CortiProjectPath)' == ''" />
<PackageReference Include="DotNetEnv" Version="3.1.1" />
<Content Include="sample\trouble-breathing.mp3" CopyToOutputDirectory="PreserveNewest" Link="sample\trouble-breathing.mp3" />
</ItemGroup>
Expand Down
86 changes: 86 additions & 0 deletions sdk/dotnet/web-api/Endpoints/AgenticEndpoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using Corti;
using Corti.Agentic;
using Corti.Agentic.Registry;
using CortiApiExamples;

namespace CortiApiExamples.Endpoints;

public static class AgenticEndpoint
{
public static void MapAgenticEndpoint(this WebApplication app)
{
app.MapGet("/agentic", Handle);
}

private static async Task<IResult> Handle(IConfiguration config)
{
if (!CortiHelpers.TryCreateCortiClient(config, out var client, out var credentialError))
{
return credentialError;
}

try
{
var listedPager = await client!.Agentic.Agents.ListAsync(
new AgenticAgentsListRequest { PageSize = 10 });
var listAgents = listedPager.CurrentPage.Items.ToList();

var createdAgent = await client.Agentic.Agents.CreateAsync(new AgenticAgentsCreateRequest
{
Name = $"SDK Example Agentic {DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}",
Description = "Example agent created via Agentic API v2.",
Lifecycle = AgentsLifecycle.Ephemeral,
});

var getAgent = await client.Agentic.Agents.GetAsync(createdAgent.Id);
var agentCard = await client.Agentic.Agents.CardAsync(createdAgent.Id);

var registryPager = await client.Agentic.Registry.Connectors.ListAsync(
new AgenticRegistryConnectorsListRequest { PageSize = 10 });
var registryConnectors = registryPager.CurrentPage.Items.ToList();

var sendMessageResponse = await client.Agentic.Agents.SendMessageAsync(
createdAgent.Id,
new AgenticAgentsSendMessageRequest
{
Message = new CommonMessage
{
Role = CommonRole.RoleUser,
Parts = [new CommonPart { Text = "Hello from SDK agentic example" }],
MessageId = $"msg-{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}",
},
});

var contextsPager = await client.Agentic.Contexts.ListAsync(
new AgenticContextsListRequest { AgentId = createdAgent.Id, PageSize = 10 });
var contexts = contextsPager.CurrentPage.Items.ToList();

var usage = await client.Agentic.Agents.UsageAsync(
createdAgent.Id,
new AgenticAgentsUsageRequest());

await client.Agentic.Agents.DeleteAsync(createdAgent.Id);

return Results.Ok(new
{
listCount = listAgents.Count,
agents = listAgents,
createdAgent,
getAgent,
agentCard,
registryConnectorsCount = registryConnectors.Count,
registryConnectors,
sendMessageResponse,
contextsCount = contexts.Count,
contexts,
usage,
deletedAgentId = createdAgent.Id,
message = "Agentic v2: list/create/get/card, registry connectors, sendMessage, contexts list, usage, delete",
});
}
catch (CortiClientApiException ex)
{
return CortiHelpers.CortiApiErrorResult(ex);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ private static async Task<IResult> Handle(
}
);

var document = await client.Documents.CreateAsync(
var document = await client.Documents.Classic.CreateAsync(
interaction.InteractionId,
DocumentsCreateRequest.FromDocumentsCreateRequestWithTemplateKey(
new DocumentsCreateRequestWithTemplateKey
Expand Down
11 changes: 6 additions & 5 deletions sdk/dotnet/web-api/Endpoints/DocumentsEndpoint.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Corti;
using Corti.Documents;
using CortiApiExamples;

namespace CortiApiExamples.Endpoints;
Expand Down Expand Up @@ -36,7 +37,7 @@ private static async Task<IResult> Handle(IConfiguration config)
});
var demoInteractionId = created.InteractionId;

var listResp2 = await client.Documents.ListAsync(demoInteractionId);
var listResp2 = await client.Documents.Classic.ListAsync(demoInteractionId);
var listDocuments = listResp2.Data?.ToList() ?? new List<DocumentsGetResponse>();

var createBody = new DocumentsCreateRequestWithTemplateKey
Expand All @@ -57,12 +58,12 @@ private static async Task<IResult> Handle(IConfiguration config)
OutputLanguage = "en",
Name = "Patient Consultation Note",
};
var createdDocument = await client.Documents.CreateAsync(demoInteractionId, createBody);
var createdDocument = await client.Documents.Classic.CreateAsync(demoInteractionId, createBody);
var documentId = createdDocument.Id;

var retrievedDocument = await client.Documents.GetAsync(demoInteractionId, documentId);
var retrievedDocument = await client.Documents.Classic.GetAsync(demoInteractionId, documentId);

var updatedDocument = await client.Documents.UpdateAsync(
var updatedDocument = await client.Documents.Classic.UpdateAsync(
demoInteractionId,
documentId,
new DocumentsUpdateRequest
Expand All @@ -77,7 +78,7 @@ private static async Task<IResult> Handle(IConfiguration config)
],
});

await client.Documents.DeleteAsync(demoInteractionId, documentId);
await client.Documents.Classic.DeleteAsync(demoInteractionId, documentId);
await client.Interactions.DeleteAsync(demoInteractionId);

return Results.Ok(new
Expand Down
11 changes: 10 additions & 1 deletion sdk/dotnet/web-api/Endpoints/GuidedDocumentsEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ private static async Task<IResult> Handle(IConfiguration config)
],
}));

var listed = (await client.Documents.ListAsync(new GuidedDocumentsListRequest())).ToList();
GuidedDocument? retrieved = listed.Count > 0
? await client.Documents.GetAsync(listed[0].Id)
: null;

// 3. Clean up
await client.Documents.Templates.DeleteAsync(template.Id);
await client.Documents.Sections.DeleteAsync(section.Id);
Expand All @@ -84,8 +89,12 @@ private static async Task<IResult> Handle(IConfiguration config)
templateId = template.Id,
sectionId = section.Id,
generatedDocument = generateResponse.Document,
sections = generateResponse.Document.Sections,
usageInfo = generateResponse.UsageInfo,
message = "Create section, create template, generate document, and cleanup completed successfully",
listCount = listed.Count,
listed,
retrieved,
message = "Create section, create template, generate (ephemeral), list/get persisted guided documents, and cleanup completed successfully",
});
}
catch (CortiClientApiException ex)
Expand Down
1 change: 1 addition & 0 deletions sdk/dotnet/web-api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
app.MapLanguagesEndpoint();
app.MapTemplatesEndpoint();
app.MapAgentsEndpoint();
app.MapAgenticEndpoint();
app.MapDocumentsEndpoint();
app.MapGuidedSectionsEndpoint();
app.MapGuidedTemplatesEndpoint();
Expand Down
15 changes: 9 additions & 6 deletions sdk/dotnet/web-api/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Corti SDK Examples – .NET Web API

A minimal **ASP.NET Core** API that demonstrates the [Corti.Sdk](https://www.nuget.org/packages/Corti.Sdk) package: token flows, interactions, recordings, transcripts, facts, codes, templates, agents, documents, **stream** and **transcribe** SDK WebSocket demos (two styles each), and **ambient** demos (async upload pipeline and real-time stream with facts mode).
A minimal **ASP.NET Core** API that demonstrates the [Corti.Sdk](https://www.nuget.org/packages/Corti.Sdk) package: token flows, interactions, recordings, transcripts, facts, codes, templates, agents, **agentic** (v2), documents (classic and guided), **stream** and **transcribe** SDK WebSocket demos (two styles each), and **ambient** demos (async upload pipeline and real-time stream with facts mode).

## Why this example exists

This is a **server-side** reference API you can run locally. It shows how to:

- **Authenticate** — Client credentials, ROPC, refresh token, authorization code, and PKCE token endpoints (optional scopes where applicable).
- **Call Corti APIs** — Interactions (list, create, get, update, delete), recordings (list, upload sample, get, delete), transcripts (list, create from sample, get status, get, delete), facts (groups, list, create, update, batch, extract), codes (ICD-10-CM, CPT), languages, templates, agents, documents (standard and guided).
- **Call Corti APIs** — Interactions (list, create, get, update, delete), recordings (list, upload sample, get, delete), transcripts (list, create from sample, get status, get, delete), facts (groups, list, create, update, batch, extract), codes (ICD-10-CM, CPT), languages, templates, agents (v1), agentic (v2), documents (classic interaction-scoped and guided).
- **Stream and transcribe** — Each demo is a **GET** that runs the SDK client in-process against sample audio (`trouble-breathing.mp3` under `sample/`), then returns a JSON payload of captured WebSocket messages. Variants: config sent after `ConnectAsync()` vs. `ConnectAsync(config)`.
- **Ambient** — `/ambient-async-end-to-end` and `/ambient-async-facts` exercise upload → transcript → document or facts extraction; `/ambient-rt-streams` exercises the real-time stream API in **facts** mode with chunked audio and `StreamEndMessage`.

Expand Down Expand Up @@ -79,9 +79,12 @@ The API listens on **port 8080** inside the container. Use `http://localhost:808
| `/codes` | Code prediction (ICD-10-CM, CPT) |
| `/languages` | List supported languages (optional query: `endpoint=streams\|transcribe\|transcripts`) |
| `/templates` | List templates, list sections, get by key (query: org, lang, status) |
| `/agents` | List, create, get, card, registry experts, message send, get task/context, delete (query: limit, offset, ephemeral) |
| `/documents` | List, create, get, update, delete document |
| `/guided-documents` | Guided templates/sections: list, create, generate (template ref and dynamic), cleanup |
| `/agents` | Agents v1: list, create, get, card, registry experts, message send, get task/context, delete (query: limit, offset, ephemeral) |
| `/agentic` | Agentic v2: list/create/get/card, registry connectors, sendMessage, contexts list, usage, delete |
| `/documents` | Classic interaction-scoped documents (`Documents.Classic`): list, create, get, update, delete |
| `/documents/generate` | Guided documents: generate (ephemeral), list persisted, get first if any; returns `Sections` headings |
| `/documents/templates` | Guided templates: list, create, get, update, versions, delete |
| `/documents/sections` | Guided sections: list, create, get, update, delete |
| `/transcribe` | Dictation **transcribe** WebSocket: `ConnectAsync()`, then `TranscribeConfigMessage`, stream sample MP3 in chunks, flush; returns JSON with captured messages |
| `/transcribe-with-config` | Same as `/transcribe` but `ConnectAsync(TranscribeConfig)` so configuration is supplied at connect |
| `/stream` | Ambient **stream** WebSocket: optional `?interactionId=` (otherwise creates an interaction), `ConnectAsync()`, then `StreamConfigMessage` (transcription mode), chunks + flush; returns JSON |
Expand All @@ -98,7 +101,7 @@ Set Corti credentials in **appsettings.json**, **appsettings.Development.json**,

### Client credentials (main)

Required for `/token`, `/token/cc`, `/token/bearer`, and most API endpoints (interactions, recordings, transcripts, facts, codes, templates, agents, documents, `/transcribe`, `/transcribe-with-config`, `/stream`, `/stream-with-config`, `/ambient-async-end-to-end`, `/ambient-async-facts`, `/ambient-rt-streams`):
Required for `/token`, `/token/cc`, `/token/bearer`, and most API endpoints (interactions, recordings, transcripts, facts, codes, templates, agents, agentic, documents, `/transcribe`, `/transcribe-with-config`, `/stream`, `/stream-with-config`, `/ambient-async-end-to-end`, `/ambient-async-facts`, `/ambient-rt-streams`):

| Key (appsettings) | Env variable | Description |
|-------------------|--------------|-------------|
Expand Down
2 changes: 1 addition & 1 deletion sdk/postman/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ All requests use the `{{host}}` variable from the selected environment, so switc

| Path | Description |
|------|-------------|
| `WebApi.postman_collection.json` | Collection: token (client credentials, ROPC, refresh, auth code, PKCE), client-variants, interactions, recordings, transcripts, facts, codes, documents, templates, agents, stream, transcribe |
| `WebApi.postman_collection.json` | Collection: token (client credentials, ROPC, refresh, auth code, PKCE), client-variants, interactions, recordings, transcripts, facts, codes, documents (classic + guided), templates, agents, agentic, stream, transcribe |
| `environments/` | Environment files with `host` set per server (JS, .NET, .NET Docker) |
| `globals/` | Optional workspace globals |
36 changes: 18 additions & 18 deletions sdk/postman/WebApi.postman_collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -223,24 +223,6 @@
},
"response": []
},
{
"name": "Guided documents",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{host}}/guided-documents",
"host": [
"{{host}}"
],
"path": [
"guided-documents"
],
"query": []
}
},
"response": []
},
{
"name": "Templates",
"request": {
Expand Down Expand Up @@ -366,6 +348,24 @@
},
"response": []
},
{
"name": "Agentic",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{host}}/agentic",
"host": [
"{{host}}"
],
"path": [
"agentic"
],
"query": []
}
},
"response": []
},
{
"name": "Transcribe",
"request": {
Expand Down
2 changes: 1 addition & 1 deletion sdk/typescript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ TypeScript/JavaScript example applications demonstrating [`@corti/sdk`](https://

| Project | Directory | Description |
|---------|-----------|-------------|
| **Express Web API** | [express-web-api/](express-web-api/) | Server-side REST API: token (client credentials, ROPC, auth code, PKCE), interactions, recordings, transcripts, facts, codes, templates, agents, documents, stream and transcribe WebSockets. Credentials via env. A Postman collection in the repo targets this API. |
| **Express Web API** | [express-web-api/](express-web-api/) | Server-side REST API: token (client credentials, ROPC, auth code, PKCE), interactions, recordings, transcripts, facts, codes, templates, agents, agentic v2, documents (classic and guided), stream and transcribe WebSockets. Credentials via env. A Postman collection in the repo targets this API. |
| **Next auth examples** | [next-auth-examples/](next-auth-examples/) | Next.js app with four auth flows (client credentials, ROPC, authorization code, PKCE). You enter credentials in forms; after a successful token exchange the app shows a success view (token + interactions list). See the [security notice](next-auth-examples/README.md#security-notice) in that project’s README before using tokens on the client. |
| **Speech to Text Applets** | [applets/](applets/) | Speech to Text applets represent components that can be built in to speech recognition applications (dictation, ambient documentation, and augmenting speech to text with agents). Use these along with available [documentation Guides](https://docs.corti.ai/stt/guides/overview) to bootstrap your build. |

Expand Down
Loading
Loading