Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Types

string literals — ordinary, verbatim and raw

"text" · @"no escapes" · """raw, multi-line"""

Three ways to write a string, all of them C#'s. The ordinary form processes escapes. The verbatim form (`@"…"`) processes none and may span lines, which is what regular expressions and Windows paths want. The raw form (`"""…"""`) processes none either, lets you write quotes plainly, and — for the multi-line shape — strips the closing delimiter's own indentation, so a block of prose lines up with the code around it without any of that alignment reaching the value.

stable1 example compiled by CItypesstringssyntax

Summary#

var a = "line one\nline two";           // escapes processed
var b = @"C:\temp\report.csv";          // no escapes; "" is a literal quote; may span lines
var c = """He said "yes" and left.""";  // no escapes; quotes written plainly

Pick by what the text contains. Escapes are convenient until the text is full of backslashes; then @"…" is clearer. Both get awkward once the text is a paragraph — which is what the raw form is for.

Signature#

formescapesquotes insidespans lines
"…"processed (\n, \t, \\, \", \uXXXX)\"no
@"…"none""yes, verbatim — every leading space is kept
"""…"""nonewritten plainlyyes, and the closing delimiter's indentation is stripped

Description#

The raw form, single line#

Everything between the delimiters, exactly:

var q = """He said "yes" and left.""";      // He said "yes" and left.

Open with more than three quotes when the text itself contains three:

var fence = """"a ``` and a """ inside"""";

The rule is that the closing delimiter is at least as long as the opening one, so the author picks a fence longer than anything inside. Same as C#.

The raw form, multi-line — and the indentation rule#

Put nothing but whitespace after the opening delimiter and the literal becomes multi-line. Then:

  • the first newline and the last newline are not part of the value;
  • the closing delimiter's indentation is stripped from every line.

That second rule is the whole reason the form exists. It lets a block of prose sit at the indentation of the code around it while none of that indentation reaches the value:

agent Auditor {
  Prompt = """
    You review expense claims.

    Meals are reimbursable up to 60 per person per day.
    """;
}

The value is You review expense claims.\n\nMeals are reimbursable up to 60 per person per day. — no leading spaces, no blank first line, no trailing newline. Written as @"…" the same block would carry four spaces on every line into the value, and written as concatenated "…" fragments it would not be readable as prose at all.

A line indented LESS than the closing delimiter is a compile error, not a partial strip. The alternative is a value whose leading whitespace depends on where in the file it was written, which nothing downstream could report. Line the text up with the closing delimiter, or move the delimiter left.

A blank line is exempt. It has no indentation to disagree with, and requiring some would mean trailing spaces on every empty line of a paragraph.

Why raw literals matter most for a prompt#

An agent's Prompt is the clearest case: it is prose, it is inherently multi-line, and it is the most important text on the declaration. The instructions a model actually receives should be readable in the source that supplies them.

Examples#

A multi-line prompt, and a verbatim path, in one app:

entity Note {
  [Required, MaxLength(4000)] string Body;
  security { allow read, create, update when IsAuthenticated; }
}

/// The multi-line raw form: indented with the code, and none of that indentation is in the value.
string Guidance() {
  return """
    Keep a note short.

    A note that needs headings is a document, and belongs somewhere else.
    """;
}

/// The single-line raw form — quotes written plainly, no escaping.
string Quoted() {
  return """She said "no" twice.""";
}

/// Verbatim: no escapes, so a backslash is a backslash.
string ExportPath() {
  return @"C:\exports\notes.csv";
}

See also#

Related

Every type, in one list

The complete vocabulary of built-in types — the scalars you can store, the collections, the two callable spellings…

Constant expressions

Some places take a value that must be known at compile time — an attribute argument, a config setting, a workflow…

the agent loop (app.Agent, Loop)

The workflow an agent's work runs INSIDE. A step of it means "run the agent until it finishes or asks for help" — the…